JVM内存管理(一)

By | 2018年5月3日

方法区:

方法区存放了要加载的类的信息(名称、修饰符等)、类的静态变量、类中定义为final类型的常量、类中的field信息、类中的方法信息。当开发人员在程序中通过Class对象的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域。

方法区域是全局共享的,在一定条件下,它也会被GC,当方法区域要使用的内存超过其允许的最大值时,就会抛出OutOfMemory的错误信息。

方法区又称为持久代,默认最小值为16M,最大值为64M,可通过-XX:PermSize及-XX:MaxPermSize来指定最小值和最大值

堆:

堆用于存储对象实例及数组值,java中所有通过new创建的对象的内存都在此分配,Heap中对象所占用的内存由GC进行回收,在32位操作系统上最大为2GB;在64位操作系统上则没有限制,其大小可通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存,默认为物理内存的1/64但小于1GB;-Xmx为JVM可申请的最大Heap内存,默认为物理内存的1/4但小于1GB。

为了避免在运行时频繁调整Heap的大小,通常将-Xms和-Xmx的值设成一样。

新生代:

大多数情况下,java程序中新建的对象都从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(From和To区)构成。

可通过-Xmn参数来指定新生代的大小,可通过-XX:SurvivorRatio来调整Eden Space及Survivor Space的大小。

 旧生代:

用于存放新生代中经过多次垃圾回收仍然存活的对象。例如:缓存对象,新建的对象也有可能在旧生代上直接分配内存。主要有两种状况:1. 大对象,可通过参数设置当对象超过多大时,就直接在旧生代分配内存。2. 大的数组对象。

旧生代所占用的内存大小为-Xmx对应的值减去-Xmn对应的值。

 PC寄存器和JVM方法栈:

每个线程均会创建PC寄存器和JVM方法栈,PC寄存器占用的可能为CPU寄存器或操作系统内存,JVM方法栈占用的为操作系统内存,JVM方法栈为线程私有,其在内存分配上非常高效。当方法运行完毕,其对应栈帧所占用的内存也会自动释放。

当JVM方法栈空间不足时,会抛出StackOverflowError的错误。

内存分配:

Java对象所占用的内存主要从堆上进行分配,堆是所有线程所共享的,因此在堆上分配内存时,需要进行加锁,这会导致创建对象开销比较大。当堆空间不足时,会触发Gc,如果GC后空间仍然不足,则抛出OutOfMemory错误信息。

  JDK为了提升内存分配的效率,会为每个新创建的线程在新生代的Eden Space上分配一块独立的空间,这块空间称为TLAB,其大小由JVM根据运行情况计算而得。

  在TLAB上分配内存时不需要加锁,因此JVM在给线程的对象分配内存时会尽量在TLAB上分配,如果对象过大或TLAB空间已用完,则仍然在堆上进行分配。因此,在编写java代码时,通常多个小的对象比大的对象分配起来更加高效。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注