1. Java 内存简介
Java 把内存划为为方法区,堆区,本地方法栈, pc 寄存器和 jvm 线程栈。
1.1. 方法区
存放类基本信息,静态变量等基本信息。默认最小值为 16mb ,最大为 64mb ,可以通过设置 -XX:PermSize 及 -XX:MaxPermSize 来设置。
1.2. 堆区
存放实例对象。所有 new 出来的对象都在此去来分配。 32 位操作系统最大为 2gb , 64 位没有限制。可通过设置 -Xms 和 -Xmx 来设置最小和最大堆内存。 -Xms :最小堆内存 -Xmx :最大堆内存。默认空余堆内存小于 40% 时, JVM 就会增大堆直到 -Xmx 的最大限制,可以由 -XX:MinHeapFreeRatio= 指定。默认空余堆内存大于 70% 时, JVM 会减少堆直到 -Xms 的最小限制,可以由 -XX:MaxHeapFreeRatio= 指定。一般情况是把 -Xms 和 -Xmx 设置大小一致,目的是为了减少 jvm 频繁调整 heap 大小。
1.2.1. 新生代
新生代又由 eden space 和两块大小相同的 survivor space 组成。 -XX:NewRatio 参数可以设置 Young 与 Old 的大小比例, -server 时默认为 1:2 。 -Xmn 可以设置新生代的大小,有文档推荐设为 Heap 总大小的 1/4 。 -XX:survivorRatio 调整 eden space 和 survivor space 的大小。
1.2.2. 旧生代
用来存放经过多次垃圾回收仍然存活的对象。新建的对象也可以直接分配在旧生代,一是大对象,通过参数 -XX : PretenureSizeThreshold 来设置,单位为字节,默认为 0 ,当创建的对象大于这个数时,就在旧生代创建。另外一种是大的数组对象,且数组中无引用外部对象。
1.3. pc 寄存器和 jvm 方法栈
每个线程都会创建 pc 寄存器和 jvm 方法栈, pc 寄存器更多可能是占用 cpu 内存和操作系统内存。 jvm 方法栈占用为操作系统内存,可通过参数 -Xss 设置其大小,单位为字节。
2. Java 内存分配
3. Java 内存回收
Java 认为程序中大部分的对象存活时间都很短,只有少部分存活时间长。 Java 将 jdk 划分为新生代和旧生代。并且提供了不同的 gc 回收方式。不管做那种类型的 gc ,都需要暂停应用。
3.1. 新生代
新生代使用 copy 算法来实现对内存的回收。 Java 提供三种方式回收新生代内存,对新生代的内存回收又通常称为 minor GC 。
3.1.1. 串行 GC
用 -XX:+UseSerialGC 标识串行 GC 。从根集合扫描新生代存活对象,根集合对象为:当前运行线程栈、常量、静态 变量和 remember set 标记对象。何为 remember set 标记对象呢 ? 旧生代对象也有可能引用新生代的对象。 Sun jdk 在给对象赋值的时候,会检查该对象是在新生代还是旧生代,如果是就生代,就做 remember set 标记,这样避免每次 gc 都去扫描旧生代,而旧生代一般都会很大。串行采用单线程回收 gc 。