知道怎么设置java的java设置jvm内存大小小

2008年10月 Java大版内专家分月排行榜第三
2012年8月 C/C++大版内专家分月排行榜第三2012年7月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。19830人阅读
技术文章(50)
本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java。这类文章网上有很多,但大多比较零碎。本文从认知过程角度出发,将带给读者一个系统的介绍。
&&&&&&&& 进入正题前首先要知道的是Java程序运行在JVM(Java& Virtual&Machine,Java虚拟机)上,可以把JVM理解成Java程序和操作系统之间的桥梁,JVM实现了Java的平台无关性,由此可见JVM的重要性。所以在学习Java内存分配原理的时候一定要牢记这一切都是在JVM中进行的,JVM是内存分配原理的基础与前提。
简单通俗的讲,一个完整的Java程序运行过程会涉及以下内存区域:
l& 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。
l& 栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。
l& 堆:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。
l& 常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中。
l& 代码段:用来存放从硬盘上读取的源程序代码。
l& 数据段:用来存放static定义的静态成员。
下面是内存表示图:
&&&&&&&& 上图中大致描述了Java内存分配,接下来通过实例详细讲解Java程序是如何在内存中运行的(注:以下图片引用自尚学堂马士兵老师的J2SE课件,图右侧是程序代码,左侧是内存分配示意图,我会一一加上注释)。
预备知识:
1.一个Java文件,只要有main入口方法,我们就认为这是一个Java程序,可以单独编译运行。
2.无论是普通类型的变量还是引用类型的变量(俗称实例),都可以作为局部变量,他们都可以出现在栈中。只不过普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此,普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。
1.JVM自动寻找main方法,执行第一句代码,创建一个Test类的实例,在栈中分配一块内存,存放一个指向堆区对象的指针110925。
2.创建一个int型的变量date,由于是基本类型,直接在栈中存放date对应的值9。
3.创建两个BirthDate类的实例d1、d2,在栈中分别存放了对应的指针指向各自的对象。他们在实例化时调用了有参数的构造方法,因此对象中有自定义初始值。
调用test对象的change1方法,并且以date为参数。JVM读到这段代码时,检测到i是局部变量,因此会把i放在栈中,并且把date的值赋给i。
把1234赋给i。很简单的一步。
change1方法执行完毕,立即释放局部变量i所占用的栈空间。
调用test对象的change2方法,以实例d1为参数。JVM检测到change2方法中的b参数为局部变量,立即加入到栈中,由于是引用类型的变量,所以b中保存的是d1中的指针,此时b和d1指向同一个堆中的对象。在b和d1之间传递是指针。
change2方法中又实例化了一个BirthDate对象,并且赋给b。在内部执行过程是:在堆区new了一个对象,并且把该对象的指针保存在栈中的b对应空间,此时实例b不再指向实例d1所指向的对象,但是实例d1所指向的对象并无变化,这样无法对d1造成任何影响。
change2方法执行完毕,立即释放局部引用变量b所占的栈空间,注意只是释放了栈空间,堆空间要等待自动回收。
调用test实例的change3方法,以实例d2为参数。同理,JVM会在栈中为局部引用变量b分配空间,并且把d2中的指针存放在b中,此时d2和b指向同一个对象。再调用实例b的setDay方法,其实就是调用d2指向的对象的setDay方法。
调用实例b的setDay方法会影响d2,因为二者指向的是同一个对象。
&&&&&&&& change3方法执行完毕,立即释放局部引用变量b。
&&&&&&&& 以上就是Java程序运行时内存分配的大致情况。其实也没什么,掌握了思想就很简单了。无非就是两种类型的变量:基本类型和引用类型。二者作为局部变量,都放在栈中,基本类型直接在栈中保存值,引用类型只保存一个指向堆区的指针,真正的对象在堆里。作为参数时基本类型就直接传值,引用类型传指针。
&&&&&&&& 1.分清什么是实例什么是对象。Class a= new Class();此时a叫实例,而不能说a是对象。实例在栈中,对象在堆中,操作实例实际上是通过实例的指针间接操作对象。多个实例可以指向同一个对象。
&&&&&&&& 2.栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。
&&&&&&&& 3.以上的栈、堆、代码段、数据段等等都是相对于应用程序而言的。每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。
&&&&&&&& 4.类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。
&&&&&&&& 以上分析只涉及了栈和堆,还有一个非常重要的内存区域:常量池,这个地方往往出现一些莫名其妙的问题。常量池是干嘛的上边已经说明了,也没必要理解多么深刻,只要记住它维护了一个已加载类的常量就可以了。接下来结合一些例子说明常量池的特性。
预备知识:
&&&&&&&& 基本类型和基本类型的包装类。基本类型有:byte、short、char、int、long、boolean。基本类型的包装类分别是:Byte、Short、Character、Integer、Long、Boolean。注意区分大小写。二者的区别是:基本类型体现在程序中是普通变量,基本类型的包装类是类,体现在程序中是引用变量。因此二者在内存中的存储位置不同:基本类型存储在栈中,而基本类型包装类存储在堆中。上边提到的这些包装类都实现了常量池技术,另外两种浮点数类型的包装类则没有实现。另外,String类型也实现了常量池技术。
public class test {
public static void main(String[] args) {
objPoolTest();
public static void objPoolTest() {
int i = 40;
int i0 = 40;
Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
Double d1=1.0;
Double d2=1.0;
System.out.println(&i=i0\t& + (i == i0));
System.out.println(&i1=i2\t& + (i1 == i2));
System.out.println(&i1=i2+i3\t& + (i1 == i2 + i3));
System.out.println(&i4=i5\t& + (i4 == i5));
System.out.println(&i4=i5+i6\t& + (i4 == i5 + i6));
System.out.println(&d1=d2\t& + (d1==d2));
System.out.println();
结果分析:
1.i和i0均是普通类型(int)的变量,所以数据直接存储在栈中,而栈有一个很重要的特性:栈中的数据可以共享。当我们定义了int
i = 40;,再定义int i0 = 40;这时候会自动检查栈中是否有<span style="font-size:18 color:#这个数据,如果有,i0会直接指向i的<span style="font-size:18 color:#,不会再添加一个新的<span style="font-size:18 color:#。
2.i1和i2均是引用类型,在栈中存储指针,因为Integer是包装类。由于Integer
包装类实现了常量池技术,因此i1、i2的<span style="font-size:18 color:#均是从常量池中获取的,均指向同一个地址,因此i1=12。
3.很明显这是一个加法运算,Java的数学运算都是在栈中进行的,Java会自动对i1、i2进行拆箱操作转化成整型,因此i1在数&#20540;上等于i2&#43;i3。
4.i<span style="font-size:18 color:#和i5
均是引用类型,在栈中存储指针,因为Integer是包装类。但是由于他们各自都是new出来的,因此不再从常量池寻找数据,而是从堆中各自new一个对象,然后各自保存指向对象的指针,所以i4和i5不相等,因为他们所存指针不同,所指向对象不同。
5.这也是一个加法运算,和<span style="font-size:18 color:#同理。
6.d1和d2均是引用类型,在栈中存储指针,因为Double是包装类。但Double包装类没有实现常量池技术,因此Doubled1=1.0;相当于Double
d1=new Double(1.0);,是从堆new一个对象,d2同理。因此d1和d2存放的指针不同,指向的对象不同,所以不相等。
1.以上提到的几种基本类型包装类均实现了常量池技术,但他们维护的常量仅仅是【-128至<span style="font-size:18 color:#7】这个范围内的常量,如果常量&#20540;超过这个范围,就会从堆中创建对象,不再从常量池中取。比如,把上边例子改成Integer
i1 = 400; Integer i2 = 400;,很明显超过了<span style="font-size:18 color:#7,无法从常量池获取常量,就要从堆中new新的Integer对象,这时i1和i2就不相等了。
2.String类型也实现了常量池技术,但是稍微有点不同。String型是先检测常量池中有没有对应字符串,如果有,则取出来;如果没有,则把当前的添加进去。
凡是涉及内存原理,一般都是博大精深的领域,切勿听信一家之言,多读些文章。我在这只是浅析,里边还有很多猫腻,就留给读者探索思考了。希望本文能对大家有所帮助!
(1) 符号引用,顾名思义,就是一个符号,符号引用被使用的时候,才会解析这个符号。如果熟悉linux或unix系统的,可以把这个符号引用看作一个文件的软链接,当使用这个软连接的时候,才会真正解析它,展开它找到实际的文件
对于符号引用,在类加载层面上讨论比较多,源码级别只是一个形式上的讨论。
当一个类被加载时,该类所用到的别的类的符号引用都会保存在常量池,实际代码执行的时候,首次遇到某个别的类时,JVM会对常量池的该类的符号引用展开,转为直接引用,这样下次再遇到同样的类型时,JVM就不再解析,而直接使用这个已经被解析过的直接引用。
除了上述的类加载过程的符号引用说法,对于源码级别来说,就是依照引用的解析过程来区别代码中某些数据属于符号引用还是直接引用,如,System.out.println(&test& &#43;&abc&);//这里发生的效果相当于直接引用,而假设某个Strings
= &abc&; System.out.println(&test& &#43; s);//这里的发生的效果相当于符号引用,即把s展开解析,也就相当于s是&abc&的一个符号链接,也就是说在编译的时候,class文件并没有直接展看s,而把这个s看作一个符号,在实际的代码执行时,才会展开这个。
参考文章:
java内存分配研究:
Java常量池详解之一道比较蛋疼的面试题:
jvm常量池:
深入Java核心 Java内存分配原理精讲:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:397403次
积分:4970
积分:4970
排名:第4742名
原创:90篇
评论:366条
(1)(5)(6)(1)(8)(6)(6)(5)(5)(1)(1)(7)(4)(4)(4)(3)(25)Java 堆内存(Heap) - 286 - ITeye技术网站
博客分类:
堆(Heap)又被称为:优先队列(Priority Queue),是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因而实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。
堆的数据结构如图所示:
Heap 是一种数据结构,而我们平时常说的Heap 其实指的是"Heap Memory"(堆内存)。
Heap 是应用程序在运行期请求操作系统分配给自己的向高地址扩展的数据结构,是不连续的内存区域。由于从操作系统/JVM 管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率比较低。但是堆的优点在于:编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间。因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定。
所以堆内存最大的特点就是:堆允许程序在运行时动态地申请某个大小的内存空间。
在JVM 中,堆(Heap)是可供各条线程共享的运行时内存区域,也是供所有类实例和数组对象分配内存的区域。
Java堆在虚拟机启动的时候就被创建,它存储了被自动内存管理系统(Automatic Storage Management System,也即是常说的“Garbage Collector(垃圾收集器)”)所管理的各种对象,这些受管理的对象无需,也无法显式地被销毁。Java堆的容量可以是固定大小的,也可以随着程序执行的需求动态扩展,并在不需要过多空间时自动收缩。Java堆所使用的内存亦不需要保证是连续的。
JVM 实现应当提供给程序员或者最终用户调节Java堆初始容量的手段,对于可以动态扩展和收缩Java堆来说,则应当提供调节其最大、最小容量的手段。
在Java 中,要求创建一个对象时,只需用new 关键字及相关的代码即可。执行这些代码时,JVM 会在堆内存中自动进行数据存储空间的分配。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因之一。
Heap 用来存储数组与new 关键字创建的对象,例如:
Student stu = new Student();
(方法中定义的基本类型的变量和对象的引用变量都在会栈内存中分配)
首先JVM 会在Heap 中分配出Student 对象存储的内存区域,并将地址返回,然后再在Stack 中创建Student 对象的引用用来存放Heap 分配的Student 地址。之后就可以在程序中使用栈中的引用对象来访问堆中的数组或对象。当使用完对象后,我们不必显式的管理堆内存释放工作,堆内存的释放会由GC(垃圾收集器)自动完成。
在HotSpot JVM 实现中Heap 内存被“分代”管理,默认的本节以此为例讲解。
JVM 的内存首先被分割成两部分:
- Heap Memory 堆内存
堆内存是我们程序运行时可以申请的内存空间,用于存储程序运行时的数据信息。
- Non Heap Memory 非堆内存
除了堆内存区域用来存放存活(living)的数据,JVM 还需要尤其是类描述、元数据等更多信息。所以这些信息统一被存放在命名为Permanent generation(永久/常驻代)的区域。
非堆内存其实就是JVM 留给自己用的,所以方法区、JVM 内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码等都在非堆内存中。
非堆内存由JVM 管理,我们无法在程序中使用。
下图为Heap 在Runtime Data Area(运行时数据区)中的位置,可以说除了Heap 都属于Non Heap(非堆内存):
Heap Memory 又被分为两大区域:
- Young/New Generation 新生代
新生对象放置在新生代中,新生代由Eden 与Survivor Space 组成。
- Old/Tenured Generation 老年代
老年代用于存放程序中经过几次垃圾回收后还存活的对象
1.Young/New Generation 新生代
程序中新建的对象都将分配到新生代中,新生代又由Eden(伊甸园)与两块Survivor(幸存者) Space 构成。Eden 与Survivor Space 的空间大小比例默认为8:1,即当Young/New Generation 区域的空间大小总数为10M 时,Eden 的空间大小为8M,两块Survivor Space 则各分配1M,这个比例可以通过-XX:SurvivorRatio 参数来修改。Young/New Generation的大小则可以通过-Xmn参数来指定。
Eden:刚刚新建的对象将会被放置到Eden 中,这个名称寓意着对象们可以在其中快乐自由的生活。
Survivor Space:幸存者区域是新生代与老年代的缓冲区域,两块幸存者区域分别为s0 与s1,当触发Minor GC 后将仍然存活的对象移动到S0中去(From Eden To s0)。这样Eden 就被清空可以分配给新的对象。
当再一次触发Minor GC后,S0和Eden 中存活的对象被移动到S1中(From s0To s1),S0即被清空。在同一时刻, 只有Eden和一个Survivor Space同时被操作。所以s0与s1两块Survivor 区同时会至少有一个为空闲的,这点从下面的图中可以看出。
当每次对象从Eden 复制到Survivor Space 或者从Survivor Space 之间复制,计数器会自动增加其值。 默认情况下如果复制发生超过16次,JVM 就会停止复制并把他们移到老年代中去。如果一个对象不能在Eden中被创建,它会直接被创建在老年代中。
新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,通常很多的对象都活不过一次GC,所以Minor GC 非常频繁,一般回收速度也比较快。
Minor GC 清理过程(图中红色区域为垃圾):
1.清理之前
2.清理之后
注意:图中的"From" 与"To" 只是逻辑关系而不是Survivor Space 的名称,也就是说谁装着对象谁就是"From"。
2.Old/Tenured Generation 老年代
老年代用于存放程序中经过几次垃圾回收后还存活的对象,例如缓存的对象等,老年代所占用的内存大小即为-Xmx 与-Xmn 两个参数之差。
堆是JVM 中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new 对象的开销是比较大的,鉴于这样的原因,Hotspot JVM 为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间,这块空间又称为TLAB(Thread Local Allocation Buffer),其大小由JVM 根据运行的情况计算而得,在TLAB 上分配对象时不需要加锁,因此JVM 在给线程的对象分配内存时会尽量的在TLAB 上分配,在这种情况下JVM 中分配对象内存的性能和C 基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配,TLAB 仅作用于新生代的Eden,因此在编写Java 程序时,通常多个小的对象比大的对象分配起来更加高效,但这种方法同时也带来了两个问题,一是空间的浪费,二是对象内存的回收上仍然没法做到像Stack 那么高效,同时也会增加回收时的资源的消耗,可通过在启动参数上增加 -XX:+PrintTLAB来查看TLAB 这块的使用情况。
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,通常会伴随至少一次Minor GC(但也并非绝对,在ParallelScavenge 收集器的收集策略里则可选择直接进行Major GC)。MajorGC 的速度一般会比Minor GC 慢10倍以上。
虚拟机给每个对象定义了一个对象年龄(age)计数器。如果对象在 Eden 出生并经过第一次 Minor GC 后仍然存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为 1。对象在 Survivor 区中每熬过一次 Minor GC,年龄就增加 1 岁,当它的年龄增加到一定程度(默认为 15 岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。
当一个Object被创建后,内存申请过程如下:
1.JVM 会试图为相关Java 对象在Eden 中初始化一块内存区域。
2.当Eden 空间足够时,内存申请结束。否则进入第三步。
3.JVM 试图释放在Eden 中所有不活跃的对象(这属于1或更高级的垃圾回收), 释放后若Eden 空间仍然不足以放入新对象,则试图将部分Eden 中活跃对象放入Survivor 区。
4.Survivor 区被用来作为新生代与老年代的缓冲区域,当老年代空间足够时,Survivor 区的对象会被移到老年代,否则会被保留在Survivor 区。
5.当老年代空间不够时,JVM 会在老年代进行0级的完全垃圾收集(Major GC/Full GC)。
6.Major GC/Full G后,若Survivor 及老年代仍然无法存放从Eden 复制过来的部分对象,导致JVM 无法在Eden 区为新对象创建内存区域,JVM 此时就会抛出内存不足的异常。
通过 可以清晰的观察出JVM 的各个过程:
从jvmstat中可以清晰的观察到汇编,加载,垃圾回收消耗的时间与各区域内存使用情况,在图中s0与s1的内存使用永远都是相斥的,即至多只有一个会在使用。
还可以使用'YourKit Java Profiler'这个强大的工具观察更多的内存及class情况,关于YourKit Java Profiler 可以参考另一篇文章。
在32位系统下可以为JVM 分配最大2GB 堆内存大小,64位则没有限制,下列是一些常用与Heap 相关的参数:
-Xms:初始堆大小,默认为物理内存的1/64(&1GB);默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制 -Xmx:最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制 -Xmn:新生代的内存空间大小,即Eden+ 2个survivor space。 在保证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。 -XX:SurvivorRatio:新生代中Eden区域与Survivor区域的容量比值,默认值为8。两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。 -Xss:每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。应根据应用的线程所需内存大小进行适当调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"-Xss is translated in a VM flag named ThreadStackSize”一般设置这个值就可以了。 -XX:PermSize:设置永久代(perm gen)初始值。默认值为物理内存的1/64。 -XX:MaxPermSize:设置持久代最大值。物理内存的1/4。
大型的应用系统常常会被两个问题困扰:
一个是启动缓慢,因为初始Heap 非常小,必须由很多major 收集器来调整内存大小。
另一个更加严重的问题就是默认的Heap 最大值对于应用程序来说“太可怜了”。根据以下经验法则(即拇指规则,指根据经验大多数情况下成立,但不保证绝对):
(1)给于虚拟机更大的内存设置,往往默认的64mb 对于现代系统来说太小了。
(2)将-Xms 与-Xmx 设置为相同值,这样做的好处是GC 不用再频繁的根据内存使用情况去动态修改Heap 内存大小了,而且只有当内存使用达到-Xmx 设置的最大值时才会触发垃圾收集,这给GC 及系统减轻了负担。
(3)当CPU 数量增加后相应也要增加物理内存的数量,因为JVM 中有并行垃圾收集器。
下面是几种断代法可用GC汇总:
GC 的默认使用情况:
老年代/永久代
串行收集器
串行收集器
并行压缩收集器
最近再仔细研究下Java 堆栈方面的细节,发现网上很多文章有很多错误的地方,我尽量去查阅官方的说法,做到大部分正确不会误导大家,如果出现哪些错误可以及时提出。
1.有的朋友会对Heap 范围这个概念有所疑惑,在Java 虚拟机规范中有这样一段原文:
The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This version of the Java Virtual Machine specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous.
大致意思是方法区逻辑意义上属于Heap(堆),但通常的做法是将两者分开,从而更加便于管理。
也就是说方法区在虚拟机规范中被当作堆的一部分,但是在具体实现中往往是将两者分开,并称为"Non-Heap"(非堆区)。
所以广义的Heap=heap + method area(老年代+新生代+方法区)。
狭义的Heap(也就是HotSpot JVM 实现)指的就是堆内存,其中分为老年代和新生代。
通常情况下我们常用的是狭义Heap,所以大家在文章未声明的情况下都可以认为Heap 所指即为JVM 中的堆内存,用来存储对象的。
2.对于习惯在HotSpot 虚拟机上开发和部署程序的开发者来说,很多人愿意把方法区称为“永久代”(Permanent Generation),本质上两者并不等价,仅仅是因为HotSpot 虚拟机的设计团队选择把GC 分代收集扩展至方法区,或者说使用永久代来实现方法区而已。对于其他虚拟机(如BEA JRockit、IBM J9等)来说是不存在永久代的概念的。即使是HotSpot虚拟机本身,根据官方发布的路线图信息,现在也有放弃永久代并“搬家”至Native Memory 来实现方法区的规划了。
这个(Non Heap Memory 非堆内存)& 指的就是方法区吧? 用来保存每个类的结构信息,比如常量池,字段,方法等信息。
方法区属于非堆内存,但不是全部,所谓非堆内存其实就是JVM 留给自己用的,所以方法区、JVM 内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码等都在非堆内存中。
Minor GC 的第二张图的两个Survivor的From 和To写反了吧?没反,其实两个区应该成为s0和s1 from 与to 只是逻辑名称而已,比如从s0复制到s1 那么s0就是from 反之亦然
是CMS吧 不是MSC.不过看起来好像是你自己做的图啊 后面那张确实不是。。。。。 已经改了
浏览: 313837 次
来自: 北京
群主你的mysql系列结束了?
学习了。翻译成中文看起来方便了。
josico 写道比较关心 tomcat的一些日志信息 如歌个 ...

我要回帖

更多关于 怎么设置java内存大小 的文章

 

随机推荐