转载自: https://www.cnblogs.com/paulwang92115/p/12251476.html 概述如果在大学里学过或者在工作中使用过 C 或者 C++ 的读者一定会发现这两门语言的内存管理机制与 Java 的不同。在使用 C 或者 C++ 编程时,程序员需要手动的去管理和维护内存,就是说需要手动的清除那些不需要的对象,否则就会出现内存泄漏与内存溢出的问题。 如果你使用 Java 语言去开发,你就会发现大多数情况下你不用去关心无用对象的回收与内存的管理,因为这一切 JVM 虚拟机已经帮我们做好了。了解 JVM 内存的各个区域将有助于我们深入了解它的管理机制,避免出现内存相关的问题和高效的解决问题。 引出问题在 Java 编程时我们会用到许多不同类型的数据,比如临时变量、静态变量、对象、方法、类等等。那么他们的存储方式有什么不同吗?或者说他们存在哪? 运行时数据区域Java 虚拟机在执行 Java 程序过程中会把它所管理的内存分为若干个不同的数据区域,各自有各自的用途。 这其中堆和方法区是线程之间共享的,而栈和程序计数器是线程私有的。
补充虽然上面的图里没有运行时常量池和直接内存,但是这两部分也是我们开发时经常接触的。所以给大家补充出来。
这里有一个概念希望大家能够清除,堆中使用分代垃圾回收算法时的永久代表方法区,它并不在堆内存中,上面的图片将其放在一起是为了说明分代垃圾回收算法会作用在这几个区域。 JDK 1.8 的改变对于方法区,它是线程共享的,主要用于存储类的信息,常量池,方法数据,方法代码等。我们称这个区域为 大部分程序员应该都见过 java.lang.OutOfMemoryError:PermGen space 异常,这里的 在 JDK 1.8 中,HotSpot 虚拟机已经没有 PermGen space 方法区这个地方了,取而代之的是一个叫 元空间与方法区最大的区别是:元空间不再虚拟机中,而是使用本地内存。默认情况下,元空间的大小仅受本地内存限制。 常量区原本在方法区中,现在方法区被移除了,所以常量池被放倒了堆中。 这样做的好处是: 这样更改的好处:
虚拟机对象揭秘对象的创建过程,最好是能记住,并且能知道每一步在做什么。
对象构成HotSpot 虚拟机中,对象在内存中的布局可以分为三块区域:对象头,实例数据和对齐填充。 对象头中包含两部分信息,第一部分用于存储对象自身运行时数据(哈希码,GC 分代年龄,锁状态标志),另一部分是类型指针,即指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。 实例数据部分存储的对象的有效信息。 对其填充起到的是占位的作用。 对象的访问定位
补充String str1 = 'abcd'; String str2 = new String('abcd'); System.out.println(str1==str2);//false 这两种方式创建的对象是有差别的,第一种方式是在常量池中,第二种方式是在堆内存中。 直接使用双引号声明创建出来的 String 对象会直接存储在常量池中。 如果不是使用常量池声明的 String 对象,可以使用 String 提供的 intern 方String.intern() 是一个 Native 方法,它的作用是:如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用。
String str1 = 'str'; String str2 = 'ing';
String str3 = 'str' + 'ing';//常量池中的对象 String str4 = str1 + str2; //在堆上创建的新的对象 String str5 = 'string';//常量池中的对象 System.out.println(str3 == str4);//false System.out.println(str3 == str5);//true System.out.println(str4 == str5);//false String s1 = new String('abc'); 这句话创建了几个对象? 先有字符串 “abc” 放入常量池,然后 new 了一个字符串 “abc” 放入 Java 堆。栈中的引用指向堆中的对象。 Java 基本类型的包装类的大部分都实现了常量池技术,即 Byte,Short,Integer,Long,Character,Boolean。除了 Boolean 之外的 5 种包装类都默认创建了 【-128 127】的缓存数据,超出此范围仍然去创建新的对象。Float 和 Double 并没有实现常量池技术。
Integer i1 = 40; Integer i2 = new Integer(40); System.out.println(i1==i2);//输出false |
|
来自: 年少一梦bnokq3 > 《JAVA》