JVM内存管理

SUN JDK在实现时遵照JVM规范,将内存空间划分为方法区,堆,本地方法栈,PC寄存器及JVM方法栈,如下图所在=示。

JVM内存管理

一 、方法区:

        方法区存放了要加载的类的信息(名称,修饰符号等),类中的静态变量,类中定义为final类型的常量、类中的Field信息、类中的方法信息,当我们在程序中通过Class对象的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域。方法区域也是全局共享的,在一定条件下它也会被垃圾回收(GC),当方法区域要使用的内存超过其允许的大小时,会抛出内存溢出(OutOfMemoy)的错误信息,在Sun JDK中这专项区域对应的Permanet Generation,又称为持久代,默认最小值为16MB,最大值为64MB,可通过-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,默认当空余堆内在小于40%时,JVM会增大Heap到-Xmx指定的大小 ,可以通过-XX:MinHeapFreeRatio=来指定这个比例;当空余堆内在大于70%时,JVM会减小Heap的大小到-Xms指定的大小,可以通过-XX:MaxHeapFreeRatio=来指定这个比例,对于运行系统而言,为避免在运行时频繁调整Heap的大小,通常将-Xms和-Xmx的值设置为一样。

    Sun JDK从1.2开始对堆采用了分代管理的方式,分为新生代(New Generation)和旧生代(Old Generation或者Tenuring Generation)。

   java对象所战胜的内存主要从堆上进行分配,堆是所有线程共享的,因此在堆上分配内存时需要进行加锁,这导致了创建对象开销比较大,当堆上空间不足时,会触发GC,GC后空间如果不足,则抛出OutOfMenory的错误消息、

1、新生代:大多数情况下java程序中新建的对象都从新生代分配内存,新生代为由Eden Space和两块相同的大小 的Survivor Space(通常又称为S0和S1或者 From和To)构成,可通过-Xmn参数来指定新生代的大小,也可以通过-XX:SurvivorRatio来调整Eden Space及Srvivor Space 的大小。不同的GC方式会以不同的方式按此值来划分Eden Space和Survivor Space。

2、旧生代:用于存放新生代中经过多次垃圾回收仍然存活的对象,例如缓存对象,新建的对象也有可能在旧生代上直接分配内在。主要有两种状况(由不同的GC实现来决定):一种为大对象,可通过在启动参数上设置-XX:PretenureSizeThreshold=2048(单位为字节,默认值为0)来代表当对象超过多大时就不在新生代上分配,而是直接在旧生代上分配,此参数在新生代采用Parallel Scavenge GC时无效,Parallel Scavenge GC会根据运行状况决定什么对象直接在旧生代上分配内存,另一种为大的数组对象,且数组中无引用外部对象。旧生代所战胜的内存大小为-Xmx对应的值减去-Xmn对应的值。

三、本地方法栈:

   本地方法栈用于支持native方法的执行,存储了每个native方法调用的状态,在Sun JDK的实现中本地方法栈和JVM方法栈是同一个。

四、PC寄存器及JVM方法栈:

        每个线程均会创建PC寄存器和JVM方法栈,PC寄存器战胜的可能为CPU寄存器或者操作系统内存,JVM方法栈占用的为操作系统内存,JVM方栈为线程私有,在内存分配上效率非常高,当方法执行完毕后,期对应的栈帧所战胜的内存就会自动释放。当JVM方栈空间不足时,会抛出StackOverflowError的错误,在Sun JDK中可以通过设置-Xss来指定其大小。

你可能感兴趣的:(jvm,java性能优化,OutOfMenory)