
上一篇讲完了java内存模型中线程私有部分(程序计数器、虚拟机栈、本地方法栈),这篇讲下全部线程公有部分html
问:元空间(MetaSpace)和永久代(PermGen)的区别?java
jdk8之后将类的元数据放在本地堆内存中,就是元空间MetaSpace,该空间jdk之前是属于永久代的。8之后没有OutOfMemoryError:PermGen space算法
元空间和永久代都是存放class的相关信息,包括class和Meta、field的信息。数组
元空间和永久代都是方法区的实现,只是实现不一样,因此说方法区只是JVM的一种规范。数据结构
JDK1.7以后原先位于方法区中的字符串常量池已经移动到了堆中。jdk8之后使用元空间(MetaSpace)替代永久代(PermGen),由于元空间划分更合理,好比说类及相关的元数据和类加载器生命周期一致,每一个加载器都会分配一个单独的内存空间。并发
MetaSpace相比PermGen的优点jvm
- 字符串常量池存在永久代中,容易出现性能问题和内存溢出
- 类的方法信息大小难肯定,给永久代的大小置顶带来困难(过小会出现永久代溢出,太大容易致使老年代溢出)
- 永久代会为GC带来没必要要的复杂性,回收效率低(永久代中的元数据的可能会随着full GC发生而进行移动,比较消耗虚拟机性能。HotSpot虚拟机的每种类型的垃圾回收器都须要特殊处理永久代中的元数据。将元数据从永久代剥离出来,不只实现了对元空间的无缝管理,还能够简化Full GC以及对之后的并发隔离类元数据等方面进行优化)
- 方便HotSpot与其余JVM如Jrockit的集成(永久代是hotspot特有的,别的VM没有永久代)
Java堆(Heap):性能
- 对象实例的分配区域(heap是个大头,占用最多的内存空间。xmx设置jvm最大可用内存)
- GC管理的主要区域(因此也称为GC堆)

jvm虚拟机规范里,java堆可使用不连续的内存空间,只要逻辑上连续便可,就像磁盘空间同样。堆空间能够是固定大小,也能够是动态扩展的(主流的虚拟机都是动态的)。若是堆中没有内存完成实例分配,且堆不能再扩展时将会抛出OutOfMemoryError异常
优化
主流的垃圾回收机制都是采用分代收集算法,因此堆能够分为新生代、老年代,再细点就有eden区、from survivor区、to survivor区,后面博客中GC再细讲。spa
问:jvm三大新能调优参数 -Xms -Xmx -Xss的含义?
- -Xss:规定了每一个线程虚拟机栈(堆栈)的大小(通常256k足够,此设置会影响并发线程数大小)
- -Xms:堆的初始值(就是jvm进程刚启动的时候分配的堆空间大小,后面运行时堆空间超过初始值,就会动态扩容至堆的最大空间)
- -Xmx:堆能达到的最大值(通常xms xmx 都设置成同样的,由于xms不够用时动态扩容,会发生内存抖动,影响程序稳定性)
问:java内存模型中堆和栈的区别?
首先须要明白 内存分配策略:
- 静态存储:编译时肯定每一个数据目标在运行时的存储空间需求(这种分配策略要求程序不容许有可变存储空间的结构存在,也不容许有嵌套、递归的结构存在。由于它们都会致使编译时没法计算准确的存储空间)
- 栈式存储:数据区需求在编译时未知,运行时模块入口前肯定(动态的存储分配,是由一个相似于堆栈的运行栈实现的,和静态的分配方式相反。可是进入一个程序模块的时候必须知道该模块的存储大小,才能对其分配内存。跟栈同样按照新进后出的方式分配内存)
- 堆式存储:编译时或运行时模块入口都没法肯定存储空间,须要动态分配(好比可变长度串、对象实例。堆由大片的可利用快或空闲块组成,堆中的内存能够按照任意顺序分配和释放)
堆和栈的区别:
- 联系:引用对象、数组时、栈里定义变量保存堆中目标的首地址(栈只存引用变量,相似指针,程序使用栈中的引用变量访问堆中的对象、数组。引用变量是普通变量,定义时在栈中分配,引用变量在程序运行到程序做用域以外后就会被释放掉,而数组、对象自己在堆中分配,即便程序运行到做用域以外(new或者产生数组的代码块以外)堆中的数组、对象的内存不会被释放,以后会被垃圾回收掉)

- 管理方式:栈自动释放,堆须要GC(JVM本身能够针对内存栈进行管理操做,并且该内存空间的释放是编译器就能够操做的内容。而堆空间在java中,jvm执行引擎是不会对其释放的操做,而是让GC回收)
- 空间大小:栈比堆小(栈里面存储的数据和自己须要的数据特性决定的。堆须要存储比较多的对象数据,通常都很大)
- 碎片相关:栈产生的碎片远小于堆(堆空间的活动空间至关于栈比较大,可能存在长期的内存分配和释放操做,并且GC不是实时的,这使得堆中的碎片逐渐累积起来。栈空间自己就是堆栈数据结构,它的操做都是一一对应的,并且内存结构相对于堆空间的简单,不容易产生碎片)
- 分配方式:栈支持静态和动态分配,而堆仅支持动态分配
- 效率:栈的效率高于堆(由于内存块自己就是个堆栈的结构,和栈空间的结构相符合,操做也简单,只存在入栈出栈两个操做。相对于堆空间,栈空间的灵活程度不够,特别是动态管理的时候,而堆空间最大优势就是动态分配,由于它在计算机底层多是个双向链表的结构,因此管理的时候操做比栈复杂不少,因此堆的效率低于栈,可是灵活度高了不少)
例子:


问:不一样JDK版本的intern()方法的区别?(主要是JDK6 VS JDK6+)String.intern()是一个Native方法,底层调用C++的 StringTable::intern
方法,源码注释:当调用 intern 方法时,若是常量池中已经该字符串,则返回池中的字符串;不然将此字符串添加到常量池中,并返回字符串的引用。
例子:

JDK6的时候存在永久代,因此VM options能够设置PermSize大小

运行就会内存溢出,这也证实了JDK6存在永久代且永久代里面由字符串常量池

JDK7 永久代移到堆中了 因此没有内存溢出的错误

JDK8 也能输出Mission Complete 可是没有永久代的设置了 
intern在jdk6和6+的区别

jdk7+是
jdk6是
详情请看:https://www.jianshu.com/p/0d1c003d2ff5 或者 https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html