Java内存模型

2020-10-23  本文已影响0人  preDatar

Java虚拟机栈可能出现两种类型的异常:

  1. 线程请求的栈深度大于虚拟机允许的栈深度,将抛出StackOverflowError。
  2. 虚拟机栈空间可以动态扩展,当动态扩展是无法申请到足够的空间时,抛出OutOfMemory异常。

本地方法栈

本地方法栈是与虚拟机栈发挥的作用十分相似,区别是虚拟机栈执行的是Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的native方法服务,可能底层调用的c或者c++,我们打开jdk安装目录可以看到也有很多用c编写的文件,可能就是native方法所调用的c代码。

2、Java7和Java在内存模型的区别在于元空间替换了永久代。

方法区是所有线程共享的。主要用于存储类的信息、常量池、方法数据、方法代码等。
方法区是JVM 的规范,永久代(PermGen space)和 Metaspace(元空间)都是HotSpot对方法区这种规范的实现。

需要多大的持久代空间取决于类的数量,方法的大小,以及常量池的大小。

在 JDK 1.8 中, HotSpot 已经没有 “PermGen space”这个区间了,取而代之的是 Metaspace(元空间)。

不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小

-XX:MetaspaceSize 初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
-XX:MaxMetaspaceSize最大空间,默认是没有限制的。

调优:-XX:MaxMetaspaceSize={unlimited}

除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:

-XX:MinMetaspaceFreeRatio在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

为啥要移除永久代

  1. 字符串存在永久代中,容易出现性能问题和内存溢出。
  2. 类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。如果动态生成类(将类信息放入永久代)或大量地执行 String.intern (将字段串放入永久代中的常量区),很容易造成 OOM。有 -XX:MaxPermSize 的上限。
  3. 永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
  4. Oracle 可能会将HotSpot 与 JRockit 合二为一。

元空间的特点

3、直接内存

NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer。 DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的限制;而DirectBuffer直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制。

直接内存的读写操作比普通Buffer快,但它的创建、销毁比普通Buffer慢(猜测原因是DirectBuffer需向OS申请内存涉及到用户态内核态切换,而后者则直接从堆内存划内存即可)。

因此直接内存使用于需要大内存空间且频繁访问的场合,不适用于频繁申请释放内存的场合。

(Note:DirectBuffer并没有真正向OS申请分配内存,其最终还是通过调用Unsafe的allocateMemory()来进行内存分配。不过JVM对Direct Memory可申请的大小也有限制,可用-XX:MaxDirectMemorySize=1M设置,这部分内存不受JVM垃圾回收管理。)

使用对外内存的原因:

上一篇下一篇

猜你喜欢

热点阅读