手打jvm栈、堆、常量池(蕴含照本宣科的弊病)
1925 2020-12-20 12:50
照本宣科的老师、ppt、教程都不会给你创建你的生长体系。
一个知识点是怎么被人类发现的,是怎么进化的。并不是按照先易后难的顺序。往往都是按照实际生活当中发生的事实和人类综合探究能力、水平层次。然后根据当时的航海或者航空需求。产生的。
所以你需要自己去总结寻找数的产生、数学的发展。大学数学和高中以下数学哪个是追求唯一解哪个是追求近似解的。java在C++虚拟机基础上运行。C++和java共同进步。python在java之后总结了java迅速迭代出来高级用法。C++的基础是过程式的C语言。C语言在windows上是汇编。
java面向对象是如何在内存中实现的。等等问题。没有人会讲给你听。只有你自己选择需要的时候才会去找人问、找资料查。而最重要的就是源码和验证。如果不能设计程序进行验证。永远也没有自信。只有看到了别人看不清、分辨不清。越有体系越深入的层次。才会更加清晰的架构细节。根基才会扎实。
过程式编程语言,只有内存。顺序摆放。将命令和数据分开,寻址已经很不错了。
当有了面向对象。希望灵活的分配对象,才能包裹的住一个对象成为一个封装。那么就需要分离栈与堆。让栈来凝聚对象格局,让堆来存储对象数据。
当有了共享数据,多线程需要与他人协作,于是又分离出一个加载类的方法区的运行时常量池来保存基本类型和java字面量
java没有python的id()方法,但是可以用“==”来判断id()的地址是不是同一个引用。
JDK1.7开始,将StringTable从常量池移动到了堆中
java存储数据在内存中只会放到三个地方:
- 局部变量放入栈、类放入堆。
- 字面量(字面值)放入常量池(而1.7后移出了永久代。1.8用元空间代替永久代实现的方法区。实际上是一个非堆的堆)。
- 类的信息在方法区、常量池也在方法区(参考2)。
- 栈帧中存储了基本数据类型和对象引用(比如字符串类型的句柄(引用)),这个引用在创建时很有可能就是通过查找比对常量池中引用所对应的对象,如果相同那么就直接从常量池中获取了同样的引用。(如果字符串常量池中已经有赋值语句右侧的字符串,那么字符串常量池里面保存的就是这个对象引用。如果字符串常量池中没有赋值语句右侧的字符串,则在在堆上创建内容,然后将推上的引用地址传给字符串常量池中,所以可以通过常量池中的对象引用找到堆中存储对象的值)
- 运行时常量池里只存引用
- class文件常量池中可能存了对象的内容(也就是值)。
- 运行时常量池本质是一个HashSet<String>。
- jdk1.6时JVM会先从堆区复制一个字符串实例到永久代中,再将其引用添加到字符串常量池中。而jdk1.7以上不会再去复制字符串实例了,在intern方法执行时在发现堆上有对应的对象之后,直接将这个对应的引用添加到字符串常量池中。
- 终于看明白了程序员dmz描绘的运行时常量池在1.6也存的是引用而不是对象的图了。他和别人的区别在于,坚持常量池是一个hashset表,所以只会存引用。但是他把别人说在常量池建立的对象放到了常量池外,但是依然在永久代中。先不说这个是不是方法区和永久代的区别。但是他细分了常量池内外。虽然大多数人把存对象和存引用都算到了1.6的常量池中。但是他能够摘出来。让1.6的常量池也只存引用,哪怕是就在边上附带着有对象。但是也不属于常量池里。这就说清楚了。实际上方法区是一个规范。并不能找出证据来打印出实际的内存地址。只能打出引用的hashcode。所以这个猜想。和别人的说法。能够理解的就不多了。
加载时由栈帧调用堆里的类,加载方法区里的类信息,执行类里面的赋值,若遇到基础类型则去引用常量池中的保存数据。
而python不管可变对象还是不可变对象,都是存在堆中。
全部评论