JVM 堆 和 本地内存比较

Java 的类实例一般在 JVM 堆上分配,而 Java 是通过 JNI 调用 C 代码来实现 Socket 通信的,那么 C 代码在运行过程中需要的内存又是从哪里分配的呢?C 代码能否直接操作 Java 堆?

为了回答这些问题,我先来说说 JVM 和用户进程的关系。如果你想运行一个 Java 类文件,可以用下面的 Java 命令来执行

 

java my.class

这个命令行中的java其实是一个可执行程序,这个程序会创建 JVM 来加载和运行你的 Java 类

操作系统会创建一个进程来执行这个java可执行程序,而每个进程都有自己的虚拟地址空间,JVM 用到的内存(包括堆、栈和方法区)就是从进程的虚拟地址空间上分配的。请你注意的是,JVM 内存只是进程空间的一部分,除此之外进程空间内还有代码段、数据段、内存映射区、内核空间等。JVM 的角度看,JVM 内存之外的部分叫作本地内存,C 程序代码在运行过程中用到的内存就是本地内存中分配的。下面我们通过一张图来理解一下。


 

那 HeapByteBuffer 和 DirectByteBuffer 有什么区别呢?HeapByteBuffer 对象本身在 JVM 堆上分配,并且它持有的字节数组byte[]也是在 JVM 堆上分配。

但是如果用HeapByteBuffer来接收网络数据,需要把数据从内核先拷贝到一个临时的本地内存,再从临时本地内存拷贝到 JVM 堆,而不是直接从内核拷贝到 JVM 堆上。这是为什么呢?这是因为数据从内核拷贝到 JVM 堆的过程中,JVM 可能会发生 GC,GC 过程中对象可能会被移动,也就是说 JVM 堆上的字节数组可能会被移动,这样的话 Buffer 地址就失效了。如果这中间经过本地内存中转,从本地内存到 JVM 堆的拷贝过程中 JVM 可以保证不做 GC。

如果使用 HeapByteBuffer,你会发现 JVM 堆和内核之间多了一层中转,而 DirectByteBuffer 用来解决这个问题,DirectByteBuffer 对象本身在 JVM 堆上,但是它持有的字节数组不是从 JVM 堆上分配的,而是从本地内存分配的。
DirectByteBuffer 对象中有个 long 类型字段 address,记录着本地内存的地址,这样在接收数据的时候,直接把这个本地内存地址传递给 C 程序,C 程序会将网络数据从内核拷贝到这个本地内存,JVM 可以直接读取这个本地内存,这种方式比 HeapByteBuffer 少了一次拷贝,因此一般来说它的速度会比 HeapByteBuffer 快好几倍。你可以通过上面的图加深理解。

那为什么HeapByteBuffer的性能比DirectByteBuffer差依然在使用呢?
这是因为本地内存不好管理,发生内存泄漏难以定位,从稳定性考虑,
HeapByteBuffer更好。



 
 
 


 

### 关于JVM内存的使用管理 #### 内存概述 内存指的是不位于Java虚拟机(JVM)中的内存区域。这部分内存由操作系统直接分配给应用程序,而不是通过JVM的标准垃圾回收机制来管理释放。因此,在某些情况下,利用内存能够提高性能并减少停顿时间。 #### 主要组成部分 JVM内存主要包括以下几个方面[^3]: - **GC**: 自身元数据存储空间。 - **JIT编译器**: 编译后的本地代码缓存区。 - **线程栈(Thread Stacks)**: 每个线程所需的私有内存块用于保存局部变量等信息。 - **类加载(Class Metadata/ClassLoaders)**: 存储已加载类型的结构描述符以及方法表等相关资料;对于旧版本JDK而言还包括永久代(PermGen),其中可能引发`java.lang.OutOfMemoryError: PermGen space`错误[^4]。 - **NIO Direct Buffers**: 提供了一种方式使得文件I/O操作可以直接访问物理地址而无需经过缓冲池转换过程,从而提高了效率。 #### 使用场景与优势 当处理大量临时性的大对象或者频繁创建销毁的对象时,如果这些对象被放置到常规的Java上,则会增加GC负担甚至导致应用响应延迟等问题。此时采用off-heap技术就显得尤为重要了——它可以有效地降低GC频率及其影响范围,并且允许开发者更精细地控制资源生命周期。 此外,像Apache Spark这样的分布式计算框架也会充分利用这一特性来进行任务执行期间所需的数据交换工作。例如设置参数`spark.executor.memory`时,默认预留一部分作为内部开销之外可用作实际运算的空间大小[^2]. ```scala // 设置Spark Executor 的总内存容量 conf.set("spark.executor.memory", "8g") ``` #### 管理挑战 尽管如此,合理规划监控仍然是必不可少的工作环节之一。因为一旦超出系统所能承受的最大限度就会触发OOM(out-of-memory)异常终止进程运行。同时也要注意避免因过度依赖而导致其他潜在风险比如安全性漏洞或是难以调试的应用逻辑缺陷等等。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值