21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
讲述:李良
时长11:42大小10.70M
为什么 JVM 在 Java 中如此重要?
从了解内存模型开始
JVM 内存模型的具体设计
1. 堆(Heap)
2. 程序计数器(Program Counter Register)
3. 方法区(Method Area)
4. 虚拟机栈(VM stack)
5. 本地方法栈(Native Method Stack)
JVM 的运行原理
总结
思考题
赞 22
提建议
精选留言(67)
- 张学磊2019-07-09String a="b"可能创建一个对象或者不创建对象,如果"b"这个字符串在常量池里不存在会在常量池创建一个String对象"b",如果已经存在则a直接reference to这个常量池里的对象; String c= new String("b")至少创建一个对象,也可能两个,因为用到new关键字,会在堆内在创建一个的String对象,它的值是"b"。同时,如果"b"这个字符串在常量池里不存在,会在常量池创建这个一个String对象"b"。
作者回复: 对的
共 3 条评论85 - Xiao2019-07-09老师,这儿其实应该说JVM内存结构更合适!JVM内存模型是一种规范,和JVM内存结构不是一个概念。其次,元空间,在Java8,不是在堆内分配的,它的大小是依赖于本地内存大小!
作者回复: 感谢Xiao同学的提醒。 我想你说的内存模型应该是指Java内存模型(JMM)吧。这里的JVM内存模型跟Java内存模型是不一样的,这里的JVM内存模型和和内存结构是一个意思。 元空间是分配的本地内存,文中开始描述不清楚(已纠正),但后面有明确说明。
36 - Liam2019-07-09请教一个问题,所以1.8开始,方法区是堆的一部分吗?也即是说,方法区的大小受限于堆
作者回复: 方法区不是堆的一部分,方法区和堆存在交集。方法区的静态变量和运行时常量池存放在堆中,但类的元信息等还是存放在了本地内存中。
共 2 条评论23 - 夏天39度2019-07-31超哥,我可以这样理解吗,方法区只是一个逻辑概念,方法区是包括元空间物理内存和堆内存
作者回复: 对的
13 - Gred2019-08-02老师,运行时变量应该都在方法区中,从java7开始只有字符串常量池移到堆中而已
作者回复: 严格来说,是静态常量池和运行时常量池,静态常量池是存放字符串字面量、符号引用以及类和方法的信息,而运行时常量池存放的是运行时一些直接引用。 运行时常量池是在类加载完成之后,将静态常量池中的符号引用值转存到运行时常量池中,类在解析之后,将符号引用替换成直接引用。 这两个常量池在JDK1.7版本之后,就移到堆内存中了,这里指的是物理空间,而逻辑上还是属于方法区(方法区是逻辑分区)。
共 3 条评论8 - 我又不乱来2019-07-09String a="b"应该会放在字符串常量池中。 String c= new String("b") 首先应该放在 堆中一份,再在常量池中放一份。但是常量池中有b了。 第一次留言。不知道理解的对不对。超哥
作者回复: 正确
7 - 发条橙子 。2019-07-20老师,这句话怎么理解 之前永久代的类的元数据存储在了元空间,永久代的静态变量(class static variables)以及运行时常量池(runtime constant pool)则跟 Java7 一样,转移到了堆中。 方法区的一部分是由永久代实现的,永久代主要存储类的静态数据以及运行时常量池并储存在堆内存中。 但是由于容易发生permen内存溢出,后来就发明了元数据空间。那我理解元空间除了存储之前方法区的类信息还包括之前放在永久代中的 静态变量 和 运行时常量池 。 文中为什么说和jdk7一样还是转移到堆中,那不是没有变化么?展开
作者回复: 是的,没有变化。
6 - 尔冬橙2019-09-02老师,我看有人说字符串常量池只放引用;那new出来除了堆中会有一个对象,如果字符串常量池没有,也会创建一个,这个对象是在堆中非字符串常量池的地方么
作者回复: 我们说的常量池一般分为静态常量池和运行时常量池,通常字符串常量是存放的引用是在运行时常量池,而字面量是存在了静态常量池。动态生成的字符串,对象是存放在堆中,如果调用intern方法,会将引用存放在常量池中。
共 2 条评论4 - 黑夜里的猫2019-07-09字符串常量不是在java8中已经被放入到堆中了吗,应该不在方法区中了,但是看到老师的图中还在方法区中
作者回复: 方法区是一个规范,并不是一个物理空间,我们这里说的字符串常量放在堆内存空间中,是指实际的物理空间。
4 - 东方奇骥2019-07-12老师,问一下,1.8静态变量和常量存储在的堆里面,那元空间里是什么?文中说之前永久带类的数据存储在了元空间,不是很理解,
作者回复: 元空间主要存储类的一些信息,包括方法、字段、类等描述类信息。
3 - 晓杰2019-07-11创建一个线程,就会在虚拟机中申请一个栈帧,这句话有问题吧 应该是创建一个线程,会创建一个栈,然后方法调用一次,就会申请一个栈帧吧
作者回复: 对的,这里是申请一个线程栈。
3 - ZHANG2019-10-31老师,是这样吗,java8中类的静态变量,运行时常量池,字符串常量池都在堆中,那元空间只有一些类的信息了,比如版本什么的。
作者回复: 是的
2 - Cain2019-07-10常量池在哪个区?堆区?栈区?方法区?静态区?方法区,静态区他俩是什么关系?
作者回复: 在逻辑空间是属于方法区。堆、栈、方法区等,这些是一种规范,是逻辑上的分区。 在物理空间中,常量池是存储在堆内存空间的。
3 - crazypokerk2019-07-09引用a和c都会放在栈中,但是a直接指向堆中的运行时常量池中的"b",而引用c会先在堆中创建一个String对象,该对象会指向运行时常量池中的"b"。
作者回复: 厉害
3 - knightyxgy2020-05-03请教老师,看了您对其他留言的回答给予了肯定:1、JVM的堆和操作系统的堆不是一个概念。2、静态常量池和运行时常量池移入的堆内存是指物理内存,逻辑上还是属于JVM对于方法区的规范。3、方法区实际上是在本地内存即堆外内存分配的 根据老师的回答理解下来,两个常量池移入的堆内存就是操作系统层次的概念,可是JVM内存无论是堆内存还是非堆内存(元空间)应该都是操作系统抽象的堆内存中分配的吧。如何理解操作系统层次的堆和JVM的堆以及本地内存之间的关系呢?展开1
- 斐波那契2019-11-23老师 看完这个 对于运行时常量池和字符串常量池有点搞不清 是不是运行时常量池包括字符串常量池还是说这两个是不同的东西?
作者回复: 两者有区别,通常方法区中有静态常量池和运行时常量池,静态常量池主要存储的是字面量以及符号引用等信息,而运行时常量池存储的是类运行加载时生成的直接引用等信息。静态常量池也包括了我们说的字符串常量池。
共 2 条评论1 - 帽子丨影2019-08-20元空间的存储位置时本地内存,请问下本地内存是个什么东西,在第一张图里没找到啊。
作者回复: 本地内存是一种非JVM堆内存
共 2 条评论2 - Alpha2019-07-09而到了 Java8,静态变量和运行时常量池与 Java7 的永久代一样,都移到了堆中。 这句没看懂。。上一句说到java7把永久代里的静态变量和运行时常量池移到堆中,这一句又说java8移了 静态变量和运行时常量池?
作者回复: 已捋顺,也就是说静态变量和运行时常量池依然存储在堆内存物理空间中。
2 - 听雨2019-07-09元空间不是本地内存吗,老师说的元空间移入堆内存是什么意思呀,不理解,是元空间属于堆内存的一部分吗?
作者回复: 而到了 Java8,永久代被元空间取代了,元空间存储静态变量... 以上这句话描述不准确。将元空间去掉。元空间是使用的本地内存,在后面讲述到了:“并且元空间的存储位置是本地内存”
1 - Jxin2019-07-09new的会在堆申请空间。所以在堆。字符串的直接声明赋值会存在字节码的常量池加载后在常量池里面。但是常量池1.8也放堆了,所以都在堆空间。
作者回复: 从实际的存储物理空间来说,都是在JVM的堆内存空间中。而从规范的逻辑空间来说,一个是在方法区的字符串常量池中,一个是在堆中。
1