jvm是如何管理jvm 内存模型的

物理内存和虚拟内存
(1)在java中,分配内存和回收内存都由JVM自动完成,甚至不需要写和内存相关的代码(2)物理内存即RAM还有寄存器(一种存储单元,用于存储计算机单元执行指令(如整形浮点等运算)的中间结果)是处理器通过地址总线连接的。地址总线:其宽度决定了一次可以存寄存器或者RAM中获取多少个bit和处理器最大的可以寻址的范围,每个地址会引用一个字节,所以如果是32位的总线则可以有4G的内存空间。(通常情况下地址总线和RAM或寄存器有相同的位数)(3)通常操作系统的内存申请空间是按照进程来管理的,每个进程间不会互相重合,操作系统保证每个进程拥有一段独立的地址空间。(逻辑上独立,物理空间不一定独立,如虚拟内存,虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。)(4)由于程序越来越庞大何设计的多任务性,物理内存无法满足要求,出现了虚拟内存,虚拟内存使得多个进程可以共享物理内存,并且逻辑上独立。虚拟内存提高了内存利用率,并且可以扩展内存空间,使得一个虚拟的地址可以映射到物理内存,文件或者其他可以寻址的存储上。如一个进程在不活动的情况下,操作系统将这个物理内存中的数据移到一个磁盘文件下(频繁地交换物理内存和磁盘上的数据,会导致效率低下,需要关注)。
内核空间和用户空间
(1)电脑的内存地址空间将被划分为内核地址空间和用户空间,程序只能使用用户空间的内存(指程序能够申请的内存)(如windows32为默认内核空间和用户空间的比例是1:1,linux32为默认的比例是1:3)(2)内核空间主要指操作系统用于程序调度、虚拟内存或者连接硬件资源等的程序逻辑。程序不能访问操作系统的空间,并且不能直接访问硬件资源,必须通过系统提供的接口调用。(每一次系统调用都会引起内核空间和内存空间的切换,这一操作比较耗时)
Java中的那些组件需要使用内存
(1).java堆:用于存储java对象的内存区域,可以通过Xmx(最大大小)和Xms(初始大小)来控制大小,默认空余堆内存少于40%时就扩大到Xmx,空余堆内存大于70%时就缩小到Xms,因此,服务器一般把xmx和xms设置成一样,避免在GC后调节堆的大小。(2).每个线程创建时,JVM都会为它创建一个运行方法栈、局部变量的堆还有操作栈。(3).类和类加载器:类和类的加载器本身同样需要存储空间,存储在永久代PermGen(属于方法区,即java堆的永久区部分)ps:
JVM是按需加载类的,隐式加载只会加载那些应用程序中明确使用到的。
加载类超过PermGen区大小的话可能会导致内存溢出,所以对于自己实现的类加载器可能会导致类的重复加载时,可能需要实现对类的卸载,需满足:
Java堆中没有对表示该类的类加载器的java.lang.ClassLoader对象的引用,
Java对中没有该类的对应加载器的java.lang.class对象的引用,
Java堆上任何该类的类加载器的任何类的所有对象都不存活。
而JVM的默认类加载器都不满足该条件,所以他们加载的类都不能卸载。
(4)NIO:NIO使用ByteBuffer.allocateDirect()方法分配内存,可以避免数据从内核空间到用户空间的复制,提高效率,但是该方法直接使用的是本机内存而不是java堆内存,直接的ByteBuffer对象可以自动清理本机缓存区,但是其只是作为GC时的一部分执行,而GC只在Java堆被填满或者显示调用System.gc()来执行(也就是自动的GC只检查Java堆是否满,而不知道NIO操作的本机内存是否需要释放。),以至于NIO在很多框架中是通过显示调用System.gc()执行NIO内存的释放的(其实2对象本身有clean方法可以释放,见jdk随笔额,heap&direct)(5)JNI:JNI使得本机代码(如C语言)可以调用java方法,JVM会准备空间以供运行本地方法,也会增加java运行时的本机内存占用。
JVM内存结构
JVM是按照运行时数据的存储结构来划分内存结构的,根据不同的格式存储在不同的区域。运行时数据包括java程序本身的数据信息和JVM运行Java程序需要的额外数据信息,java虚拟机规范将Java运行时数据分为6种:PC寄存器数据、Java栈、堆、方法区、本地方法区、运行时常量池。
PC寄存器数据:
用于保存当前执行程序的内存地址,也就是记录某线程当前执行的方法的那一条指令,如线程的执行被中断后就会依靠这些数据来恢复(JVM规范之定义了对java方法需要记录指针,对本地方法则没有规范)
java栈与线程相关联,每创建一个线程就会为该线程创建一个栈,而线程中运行的每一个方法则与栈中的每一个栈帧关联起来,栈帧中包含局部变量,操作栈,方法返回值等。每一个方法完成,就会弹出栈帧的元素(操作栈的栈顶元素),作为返回值,清除这个栈帧。java栈的栈顶就是当前正在执行的活动栈,PC寄存器会指向这个方法的地址。Java栈和线程对应起来,这些数据不是线程共享的,不存在一致性问题
存储Java对象的地方,由于时所有线程共享的,所以需要关心数据的一致性问题。方法区:
用于存储类结构信息,如常量池、域,方法数据、方法体,构造函数、包括类中的专用方法、实力初始化、接口初始化等
方法区同样属于java堆的永久代
如果使用动态编译时要注意这部分是否能满足类的存储
这个区域并不像其他java堆一样频繁地被GC回收
运行时常量池:
包括编译器的数字常量,方法或者域的引用。(注意,这一区域属于方法区)
本地方法栈:
JVM为运行native方法准备的空间。由于很多native方法是用c语言实现的,所以又叫C栈。这个区域jvm并没有严格的限制,由不同的JVM实现者自由实现。
JVM内存分配策略
静态内存分配策略:在编译期间必须知道内存空间(8个基本类型)的大小才可以分配(所以可以在编译期间分配内存,但java栈中的局部变量和引用等数据同样使用静态内存分配,该空间大小是在编译期间知道,但是在程序加载时才正式分配的,并且这一部分内存在java栈上分配),不允许可变数据类型或者递归、嵌套等结构的出现。
栈内存分配:不需要在编译时知道程序对数据的需求、但在进入程序模块时必须知道数据的要求才可以分配内存。并且按照后进先出的原则进行内存的分配
堆内存分配:可以在运行到相应代码才知道内存空间的大小,灵活但是效率较差
JVM的内存分配主要基于堆和栈,
栈的分配时和线程绑定的,为每一个线程创建一个栈,为线程每调用一个新的方法创建一个栈帧
栈中主要保存基本类型数据和对象的句柄(引用、指针),栈的数据大小和生存期都必须是确定的,而本地变量和操作栈的大小都可以在编译时(class字节码)确定
存取速度比堆要快,仅次于寄存器,这也是为什么运算要留在操作栈中执行
栈的内存分配是在程序运行时进行的,只是分配的大小是在编译时确定的
堆可供所有线程访问,主要存放实例数据,由于时动态分配内存大小的,所以存取速度较慢,同样通过GC回收内存
新对象如何分配内存:根据对应Constant_Class_info类型数据执行new指令,赋值,调用init初始化构造器最后才赋值给变量(所以在初始化完成前不应该把实例指针公布,可类比&对象逸出&的问题),栈中存放的只是指针(引用),而真正的实例数据是存放在堆中的
堆在运行时请求操作系统分配内存,灵活但效率低
JVM内存回收策略
静态内存的分配和回收:类中的局部变量和对象的引用都是静态内存分配的(这一部分内存空间在栈上分配),在编译时这一部分空间已经确定,只是在程序被加载时一次性分配,而当方法运行结束时随着对应栈帧的撤销回收。
动态内存分配和回收:像实例等数据只有在JVM解析类对象后才能知道具体需要分配多少空间,并且堆中的这些数据只有在对象不再被引用时才会被回收。只要某个对象不再被其他活动对象所引用就可以被回收,而活动对象是指可以被根集合对象所到达的对象。根集合对象所包含的对象跟jvm具体实现有关,但是大都会包含如下一些元素:方法中局部变量的引用、java操作栈中的对象引用、常量池中的对象引用、本地方法中持有的对象引用、类的class对象(当该Class对象不再被使用时同样会被回收)。
基于分代的垃圾收集算法:分为young、old、perm三个区
young区分为eden区和两个survivor区,eden区满后会触发minorGC,minorGC后仍存活的对象将放到survivor区(若另一个survivor区存在活动对象将放到同一个区中,保证一个survivor区是空的)old区中已满将会触发FullGC,old区中存放的是:
Young的survivor区中已满后minorGC仍然存活的对象
survivor区中足够老的对象
Eden中已满,并且minorGC后存在,并因为servivor已满无法存放的对象。
perm区主要存放类的class对象,只有在FullGC时才会被回收
三类垃圾收集算法,Serial Collector、Parallel Colllector、CMS Collector
Serial Collector
JVM在client模式下的默认的GC方式(可以通过配置jvm参数 -XX:+UserSerialGC来配置实用该算法)-XX:+PrintGCDetails 可以配置打印GC日志。所有创建的对象都将在Eden区分配,如果创建的对象超过Eden区的大小或者超过PretenureSizeThreshold配置(-XX:PretenureSizeThreshold=123)参数的大小都只能在old区分配。当Eden区空间不足时会触发minorGC,但是触发minorGC之间会检查晋升到Old区的平均对象大小是否大于old的剩余空间,如果大于则触发FullGC,如果小于则根据HandlePromotionFailure(是否允许担保失败)参数,如果为true则仅触发MinorGC,否则触发FullGC。MinorGC时除了将Eden区的非活动对象回收外,还会把一些年老的对象晋升到Old区,而这个年老对象的&岁数&则通过 -XX:MaxTenuringThreshold=10设置(在survivor的from/to区之间移动一次则为一岁),另外如果To的Servivor区空间不足移入对象时,这些对象也会直接放入Old区。如果old区或者Perm区空间不足时就会触发FullGC。GC时因为是串行的,所以动作是单线程完成的,JVM中的其他应用程序会全部停止。
Parallel Collector
Parallel&GC根据MinorGC和FullGC的不同分为三种,分别是ParNewGC、ParallelGC和ParallelOldGC。
ParNewGC:可以通过参数 -XX:+UseParNewGC参数来指定,与Serail Collector相似,只是回收是多线程并行的,并且通过一个UseAdaptiveSizePolicy配置参数来控制对象经过多少次回收后可以直接放入old区。ParallelGC:是server模式JVM下的默认GC方式,可以通过 -XX:+UserParallelGC参数来强制指定,并行回收的线程数可以通过 -XX:ParallelGCThreads来指定,这个值有个计算公式,如果cpu核数小于8,则可以和核数一样,如果大于8值为:3+(核数*5)/8,可以通过 -Xmn:10m来控制Young区的大小,而Eden、FROM区的大小比例可以通过 -XX:SurvivorRatio=8来设置Eden和FromSpace的比值是8:1(当然To区也占1)。当在Eden区中申请内存空间时,如果Eden区不够,则比较当前申请空间时否大于Eden的一半,是的话则直接在old中分配,不是的话则会执行MinorGC,但是执行MinorGC之前会检查old区的平均晋升大小是否大于剩余空间,大于则触发FullGC,并且在执行FullGC后会再一次检查old的晋升的平均大小是否大于剩余空间,不是的话会再次触发FullGC,也就是说可能会触发两次FullGC。,Young区的晋升规则可以通过以下参数设置:AlwaysTenure:默认为false,为true则表示只要在MinorGC时存活则晋升,NeverTenure,默认为false,是true则永不晋升。如果上面两个参数都没有配置的情况下设置UseAdaptiveSizePolicy,则启动时将以InitialTenuringThreshold值作为存活次数的阀值,并且在每次GC后调整。如果不使用UseAdaptiveSizePolicy则将以MaxTenuringThreshold为准(通过-XX:-UseAdaptiveSizePolicy设置)另外如果MinorGC时Servivor的To区空间不够,也会直接放到old区。old或者Perm区满时会触发FullGC,如果配置了参数ScavengeBeforeFullGC则在FullGC之前会触发MinorGCPrarllelOldGC:可以通过 -XX:+UseParallelOldGC参数来强制指定,同样可以通过-XX:ParallelGCThreads来指定线程数,这个值有个计算公式,如果cpu核数小于8,则可以和核数一样,如果大于8值为: 3+(核数*5)/8。与ParallelGC的不同在于FullGC,它的FullGC动作为清空整个Heap对中的垃圾对象,清楚Perm区中已经被卸载的类信息,并进行压缩,而ParallelGC只清楚部分heap堆中的垃圾对象,并对部分空间进行压缩。
CMS Collector
可以通过 -XX:+UseConcMarkSweepGC来指定,并发的默认线程为4,也可以通过ParallelCMSThreads指定。CMS Collector使用CMS GC、Minor GC、FullGC。而CMS GC不同于其他两种GC,触发规律是基于Old区、和Perm区的使用率(触发后回收对应old或perm区的内存),达到一定比例就会触发(默认是92%),该比例可以通过CMSInitiatingOccupancyFraction来指定,另外设置让Perm区也使用CMS GC可以通过参数 -XX:+CMSClassUnloadingEnabled来指定。这个模式下的minorGC与Serial Collector基本一致,只是采用多线程。FullGC只在两种情况触发,一种是Eden分配失败后分配到To区,To区满分配到Old区,Old区不够则触发FullGC,另外一种是当CMS GC向Old申请内存失败时会触发FullGC。Hotspot1.6下使用这种算法并显示调用System.gc(如Nio可能需要显示调用),且设置了ExplicitFCInvokesConcurrent参数,将会导致内存泄露。
内存问题分析
日志格式:[GC [&Collector&:&starting occupancy1& -& &ending occupancy1& (total size1) , &paise time1& secs ]
&starting occupancy2& -& &ending occupancy2& (total size2), &paise time2& secs ]
&Collector& 收集器的名称 &starting occupancy1&Young区GC前内存&endingoccupancy1&Young区GC后内存&paise time1&YOUNG区局部收集时JVM的暂停时间&starting occupancy2&表示JVMHeap GC前内存&endingoccupancy2&表示JVMHeap GC后内存&paise time2&GC过程中JVM的暂停总时间
GC日志对内存泄露的判断:
根据&starting occupancy1& - &ending occupancy1&得到young区被回收或晋升的内存大小,根据&starting occupancy2& - &ending occupancy2&得到当前整个堆的大小变化,两者的差值就是young区晋升到Old区的值
假如&ending occupancy2&随时间的延长一直增长,并且伴随频繁的GC,则很有可能是内存泄露,可使用jstat工具分析
堆快照的分析,可以通过参数: -XX:+HeadDumpOnOutOfMemoryError来配置在内存耗尽时记录下内存快照,同时可以通过-XX:HeadDumpPath来指定文件路径,这个文件的命名格式如java_[pid].hprof
JVM Crash日志分析:
可以通过-XX:ErrorFile = /tmp/log/hs_error_%p.log来指定jvm的日志文件
文件信息主要分为四种,退出原因分类、导致退出的Thread信息(栈信息,具体哪行代码出错)、退出时的Process状态信息(所有线程及线程处于的状态,jvm的堆信息)、退出时与操作系统相关信息
退出原因主要三种:
EXCEPTION_ACCESS_VIOLATION:运行的是JVM自己的代码,很可能是JVM的BUG
SIGSEGV:JVM在执行本地代码或者JNI的代码,很可能是第三方本地库有问题
EXCEPTION_STACK_OVERFLOW:这个是本地栈溢出的错误,可以将JVM的栈的尺寸调大,主要是两个参数-Xss 和 -XX:StackShadowPages=n
阅读(...) 评论()JVM原理以及JVM内存管理机制_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
JVM原理以及JVM内存管理机制
&&JVM简介以及内存管理
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩1页未读,
定制HR最喜欢的简历
你可能喜欢博客分类:
----------~开篇分享一句话:【纸上得来终觉浅,绝知此事要躬行】~---------------------------------------
前置了解知识:
内存申请过程
1、JVM会试图为相关Java对象在Eden中初始化一块内存区域;
2、当Eden空间足够时,内存申请结束。否则到下一步;
3、JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
4、Survivor区被用来作为Eden及old的中间交换区域,如果Survivor不足以放置eden区的对象,如果old区有空闲,那么直接放置在old区,Survivor区的对象会被移到Old区
5、当old区空间不够时,JVM会在old区进行major collection;
完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"Out of memory错误";
1、jvm优先分配在eden区
2、当Eden空间足够时,内存申请结束。
证明:
jvm参数设置:
-Xmx20M -Xms20M -Xmn10M -verbose:gc
-XX:SurvivorRatio=8 -XX:+PrintGCDetails
其中:
-Xmx20M : 堆最大内存是20M
-Xms20M: 初始化也是20M
-Xmn10M :新生代10M,老年代10M
-verbose:gc& 输出退出后的日志
-XX:SurvivorRatio=8:eden 为8M s0 s1 各1M
-XX:+PrintGCDetails:打印gc日志的详情
public class TestEden {
public static void main(String[] args) {
byte[] b1 = new byte[];
日志输出:
def new generation
total 9216K, used 2704K [0x03accc0000)
eden space 8192K,
33% used [0x03acd6c0000)
from space 1024K,
0% used [0x042ccc0000)
space 1024K,
0% used [0x043ccc0000)
tenured generation
total 10240K, used 0K [0x044cecec0000)
the space 10240K,
0% used [0x044cccec0000)
compacting perm gen
total 12288K, used 2143K [0x04ecacec0000)
the space 12288K,
17% used [0x04ecd7fe0, 0x050dac0000)
No shared spaces configured.
通过分析main方法中申请2m的内存,内存分配到了eden区。from to tenered区都是没有被使用。
3、JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
证明:
jvm参数设置同上
代码:
public class TestEden {
public static void main(String[] args) {
byte[] b1 = new byte[/10];
byte[] b2 = new byte[*9/10];
[GC [DefNew: 1250K-&K), 0.0015682 secs] 1250K-&K), 0.0016006 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
def new generation
total 9216K, used 8560K [0x26eaaa0000)
eden space 8192K,
92% used [0x26eafc308, 0x276a0000)
from space 1024K, 100% used [0x277aaa0000)
space 1024K,
0% used [0x276aaa0000)
tenured generation
total 10240K, used 38K [0x278aaa0000)
the space 10240K,
0% used [0x278aaa9a00, 0x282a0000)
compacting perm gen
total 12288K, used 366K [0x282aeac2a0000)
the space 12288K,
2% used [0x282afba28, 0x282fbc00, 0x28ea0000)
ro space 8192K,
67% used [0x2c2ac802f30, 0x2cx2caa0000)
rw space 12288K,
53% used [0x2caadx2dx2d6a0000)
分析:
程序执行逻辑 先申请了1M的内存,然后再次申请8M的内存,考虑内存本身结构会占用内存空间为了避免边界都以9/10的比例来申请。
结果:
先分配了解决1M的内存在eden区,因为再次申请接近8M的内存时,eden区不够,发生了一次young gc,1M的内存分配到了from区,接近8M的内存放在了eden区。
[GC [DefNew: 1250K-&K), 0.0015682 secs] 1250K-&K), 0.0016006 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
其中
9216K 为eden+from = 8M+1M=9M
19456K 为Xmx-to = 20M-1M = 19M
1250K-&1024K :本次young gc 年轻代内存的变化
1250K-&1062K :本次young gc 总堆内存的变化
4、Survivor区被用来作为Eden及old的中间交换区域,如果Survivor不足以放置eden区的对象,如果old区有空闲,那么直接放置在old区,Survivor区的对象会被移到Old区
证明:
jvm参数设置同上
程序如下:
public class TestEden {
public static void main(String[] args) {
byte[] b1 = new byte[];
byte[] b2 = new byte[];
System.out.println(b1+""+b2);
日志输出:
[GC [DefNew: 5448K-&140K(9216K), 0.0051311 secs] 5448K-&K), 0.0051644 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[B@c17164[B@1fb8ee3
def new generation
total 9216K, used 5511K [0x26eaaa0000)
eden space 8192K,
65% used [0x26eadeb58, 0x276a0000)
from space 1024K,
13% used [0x277ac32a8, 0x278a0000)
space 1024K,
0% used [0x276aaa0000)
tenured generation
total 10240K, used 5120K [0x278aaa0000)
the space 10240K,
50% used [0x278adadaa0000)
compacting perm gen
total 12288K, used 366K [0x282aeac2a0000)
the space 12288K,
2% used [0x282afbb28, 0x282fbc00, 0x28ea0000)
ro space 8192K,
67% used [0x2c2ac802f30, 0x2cx2caa0000)
rw space 12288K,
53% used [0x2caadx2dx2d6a0000)
分析:首先程序申请了5M的内存,放在了eden区,然后再次申请5M的内存,eden区不够,发生young gc,5M放置在from区,依然不够,故直接放置old 区
结果:eden区 /1024=5M
old区:/1024=5M
5、如果eden区不够,from区也承载不了,恰old区也已承载不了,那么会full gc
证明:
jvm参数配置同上
java代码:
public class TestEden {
public static void main(String[] args) {
byte[] b1 = new byte[];
byte[] b2 = new byte[];
byte[] b3 = new byte[];
日志输出:
[GC [DefNew: 4424K-&140K(9216K), 0.0056340 secs] 4424K-&K), 0.0056837 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[GC [DefNew: 5260K-&140K(9216K), 0.0008662 secs][Tenured: 4096K-&140K(10240K), 0.0084034 secs] 9356K-&140K(19456K), [Perm : 366K-&366K(12288K)], 0.0093567 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
def new generation
total 9216K, used 163K [0x26eaaa0000)
eden space 8192K,
2% used [0x26eaec8fc8, 0x276a0000)
from space 1024K,
0% used [0x276aaa0000)
space 1024K,
0% used [0x277aaa0000)
tenured generation
total 10240K, used 8332K [0x278aaa0000)
the space 10240K,
81% used [0x278acca0000)
compacting perm gen
total 12288K, used 366K [0x282aeac2a0000)
the space 12288K,
2% used [0x282afba68, 0x282fbc00, 0x28ea0000)
ro space 8192K,
67% used [0x2c2ac802f30, 0x2cx2caa0000)
rw space 12288K,
53% used [0x2caadx2dx2d6a0000)
分析:
1、先申请了4M内存,放在eden区。
2、然后申请5M内存时,发生了young gc,无奈4M被安置在了old区,5M放在了eden区
3、再次向eden区申请8M的时候,eden区不够,同时8M还是放不下eden区,于是要full gc,full gc前先进行了young gc,5M 因为没有引用被清理,8M放在old区时,old区满,故full gc 4M也被清除old区。
结果:10240K,& 81% used& 为8M放在了old区
如果old区不够,会发生错误 java.lang.OutOfMemoryError: Java heap space
public class TestEden {
public static void main(String[] args) {
byte[] b1 = new byte[];
byte[] b2 = new byte[];
byte[] b3 = new byte[];
[GC [DefNew: 4424K-&140K(9216K), 0.0057531 secs] 4424K-&K), 0.0058056 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC [DefNew: 5260K-&140K(9216K), 0.0008379 secs][Tenured: 4096K-&K), 0.0092434 secs] 9356K-&K), [Perm : 366K-&366K(12288K)], 0.0101605 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
[Full GC [Tenured: 4236K-&K), 0.0075081 secs] 4236K-&K), [Perm : 366K-&365K(12288K)], 0.0075750 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at test.test.TestEden.main(TestEden.java:8)
def new generation
total 9216K, used 251K [0x26eaaa0000)
eden space 8192K,
3% used [0x26eaedefd0, 0x276a0000)
from space 1024K,
0% used [0x276aaa0000)
space 1024K,
0% used [0x277aaa0000)
tenured generation
total 10240K, used 4233K [0x278aaa0000)
the space 10240K,
41% used [0x278acccca0000)
compacting perm gen
total 12288K, used 365K [0x282aeac2a0000)
the space 12288K,
2% used [0x282afb688, 0x282fb800, 0x28ea0000)
ro space 8192K,
67% used [0x2c2ac802f30, 0x2cx2caa0000)
rw space 12288K,
53% used [0x2caadx2dx2d6a0000)
分析:
4M 先是放在eden区,5M申请时gc 4M转入old区,5M留在了eden区,8M申请时,发生gc5M在eden区被清理,因为eden区不够8M,所以分配到old区,old区发生full gc,full gc依然腾不出空间,报错。
注意:5M是在eden区gc时被清理,理由:[GC [DefNew: 5260K-&140K(9216K), 0.0008379 secs][Tenured: 4096K-&K), 0.0092434 secs] 9356K-&K), [Perm : 366K-&366K(12288K)], 0.0101605 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 日志显示(Tenured: 4096K-&K))无变化,但是eden区和堆总内存变化(DefNew: 5260K-&140K(9216K), 9356K-&K));
浏览: 167127 次
来自: 北京
有用有用有用
小侠有点帅哦 写道此流怎么关闭新春这个实现 可以不关闭的,哈哈 ...
此流怎么关闭新春
写的很好为什么初始化参数,年轻代-Xmn10M def new ...
应该是跟共享域名思路差不多,根据cookie的key作判断
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 设置jvm内存参数 的文章

 

随机推荐