首页 > 编程知识 正文

java字符串所占内存(字符串池和常量池有什么区别)

时间:2023-05-06 10:35:30 阅读:69353 作者:2431

在讲述这些之前,我需要一些预备知识:

可以从两个方面看到Java的内存结构。

从这个角度看,Java内存结构包括以下部分:

1、堆栈区域:编译器自动分配释放,具体方法执行结束后,系统自动释放JVM内存资源。

其作用是保存局部变量的值,包含以下内容。 1 .用于保存基本数据类型的值: 2 .保存类的实例,该实例是对堆对象的引用。 也可以用于保存加载方法时的框架。

2、堆:一般由程序员分配释放,JVM不定期看这个对象,如果没有引用就回收这个对象。

它用于存储动态生成的数据,如new出现的实例、字符数组等。 请注意,创建的对象只包含属于各自的成员变量,不包含成员方法。

因为同一类中的对象都有各自的成员变量,并存储在各自的堆中。 但是,他们共享该类的方法,而不是每次创建对象时都复制成员方法。

3、代码区域:存储程序中方法的二进制代码,且多个对象共享一个代码空间区域。

4、数据区:存储静态定义的静态成员。

5、常量池: JVM按加载类型维护常量池。 常量池是这种类型使用的常量的有序集合。 包含对直接常数(基本类型、字符串)和其他类型、方法和字段的符号引用。 池中的数据通过索引访问,就像数组一样。 常量池在Java动态链接中起着核心作用,因为常量池包含对其他类型、方法和字段的所有符号引用。 常量池位于堆中。

下图大致显示了JAVA的内存分配

二.从操作系统上的流程角度出发。

请注意,JVM规范中描述的抽象JVM概念和实际实现并不一定是一对一的。

接下来,我们来看看代码示例和注释。

公共类测试字符串常数{

publicstaticvoidmain (string args [ ] ) {

//字符串常量,分配给常量池并由编译器对其进行优化的Interned table

//也就是说,如果字符串已经存在,则s2也直接指向“hello”,而不是重复创建同一对象。

String s1='hello ';

String s2='hello ';

//new出现的对象被分配到heap。S3和s4中,指示的字符串内容相同,但是是2个不同的对象。

//所以比较==的话,其保存的引用不同,所以不相等

strings3=新字符串(world );

strings4=新字符串(world );

system.out.println(S1==S2;//真

system.out.println(S3==S4 ); //false

system.out.println(S3.equals ) S4 );//真

//String重写了equals方法,并比较了内容是否相等。

}

}

现在,我们将更详细地讨论上面的示例代码中提到的编译器优化。 请看下面的代码示例:

类a {

隐私字符串a=' aa ';

公共布尔方法数据库

String b='bb ';

final String c='cc ';

返回假;

}

}

“aa”和“bb”字符串对象根据JVM规范位于Java heap中,在JDK8之前的HotSpot VM实现中位于PermGen中,在来自JDK7的HotSpot VM中位于常规Java heap中(“cc

这些字符串对象属于interned String。 String是Java对象,必须存在于Java heap中,如JVM规范定义。 互联字符串也不例外。 Interned String的特别之处在于,JVM具有一个对Interned String的引用的字符串表,以防止内容相同的字符串对象重复intern。 (这里是编译器的优化)

虽然没有规定此StringTable如何实现JVM规范,但通常只是保存对String对象的引用,而不是保存String对象的内容。

从JVM规格看a、b、c变量:

作为a类的对象实例字段,变量a与a类的实例一起位于Java heap中。

b变量作为局部变量位于Java线程堆栈中。

c变量也是局部变量,但有final修饰,被初始化为常数值,因此c是常数。 它可能会被优化,也可能像b一样作为局部变量位于Java线程堆栈中。

从HotSpot VM虚拟机的实现来看:

方法数据库) )

解释执行时,输入的字节码是怎样的就会怎样执行,而由于javac的实现不会优化掉变量b,所以调用methodB()时它一定会在Java线程栈上的局部变量区里;当字节码里变量c存在时,它也跟b一样在Java线程栈的局部变量区。

当methodB()被JIT编译执行时,由于局部变量b、c都没有被使用,所以它们经过JIT编译后就消失了,调用methodB()不会在栈上给b或c变量分配任何空间。

通过以上相信大家对于字符串常量的分配区域以及java的内存分配有了一个较为形象的了解。

下面是一些相关知识点的补充与注意事项:

1.分清什么是实例什么是对象。Class a= new Class();此时a叫实例,而不能说a是对象。实例在栈中,对象在堆中,操作实例实际上是通过实例的指针间接操作对象。多个实例可以指向同一个对象。

2.栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。

3.以上的栈、堆、代码段、数据段等等都是相对于应用程序而言的。每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。

4.类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。