精华内容
下载资源
问答
  • 我们知道JDK1.8中取消了永久代,区而代之使用了元空间来实现方法区。话虽如此,但是关于字符串常量池和运行时常量池的模棱两可的说法一直都是争论不休的。 1)方法区包含哪些内容? 方法区包含哪些内容,摘录自...


            我们知道在JDK1.8中取消了永久代,区而代之使用了元空间来实现方法区。话虽如此,但是关于字符串常量池和运行时常量池的模棱两可的说法一直都是争论不休的。

    1)方法区包含哪些内容?

    方法区包含哪些内容,摘录自《java虚拟机规范-第8版》:
    在这里插入图片描述
    方法区包含:
            运行时常量池
            自动和方法数据
            构造函数和普通方法的字节码内容
            一些特殊方法
    这里虽然没有说明“字符串常量池”,但是它也是方法区的一部分。

    2)运行时常量池存在什么地方?

    下面是《深入理解Java虚拟机》一段摘录:
    在这里插入图片描述
    能够看到
            运行时常量池是在方法区中
            对于运行时常量池,《Java虚拟机规范》并没有做任何细节的要求,不同提供商实现的虚拟机可以按照自己的需要来实现这个内存区域

    3)取消永久代后,方法区的实现?

    在这里插入图片描述

    取消永久代后,使用元空间来实现方法区。
            在JDK1.8中,把JDK 7中永久代还剩余的内容(主要是类型信息)全部移到元空间中。注意这里的剩余内容:说明原来移除从永久代移出的字符串常量池,静态常量,在更换了方法区实现后,并没有顺势进入到元空间,那么它们到哪里去了呢?

    4)字符串常量池和运行时常量池究竟去了哪里?

            在JDK1.8中,使用元空间代替永久代来实现方法区,但是方法区并没有改变,所谓"Your father will always be your father",变动的只是方法区中内容的物理存放位置。正如上面所说,类型信息(元数据信息)等其他信息被移动到了元空间中;但是运行时常量池和字符串常量池被移动到了堆中。但是不论它们物理上如何存放,逻辑上还是属于方法区的。

            JDK1.8中字符串常量池和运行时常量池逻辑上属于方法区,但是实际存放在堆内存中,因此既可以说两者存放在堆中,也可以说两则存在于方法区中,这就是造成误解的地方。

            关于佐证运行常量池和字符串常量池被移动到了堆中,可以参考这个博客:https://mp.weixin.qq.com/s__biz=MzI4NDY5Mjc1Mg==&mid=2247485613&idx=1&sn=b2b1679033d24e965a3dd73dfab6dfaa&chksm=ebf6d0d2dc8159c4ae291d99e9c337b0cdb05578ecf7bb43671ad02cdbecfdf916a98ab18929&scene=27#wechat_redirect

            其实,移除永久代的工作从JDK1.7就开始了。JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。但永久代仍存在于JDK1.7中,并没完全移除,譬如符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap。我们可以通过一段程序来比较 JDK 1.6 与 JDK 1.7及 JDK 1.8 的区别,以字符串常量为例:

    package com.paddx.test.memory;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class StringOomMock {
        static String  base = "string";
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            for (int i=0;i< Integer.MAX_VALUE;i++){
                String str = base + base;
                base = str;
                list.add(str.intern());
            }
        }
    }
    

            这段程序以2的指数级不断的生成新的字符串,这样可以比较快速的消耗内存。我们通过 JDK 1.6、JDK 1.7 和 JDK 1.8 分别运行:
    在这里插入图片描述
    在这里插入图片描述
            从上述结果可以看出,JDK 1.6下,会出现“PermGen Space”的内存溢出,而在 JDK 1.7和 JDK 1.8 中,会出现堆内存溢出,并且 JDK 1.8中 PermSize 和 MaxPermGen 已经无效。因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中

    4)元空间是什么?

            元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:

            -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。

            -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

    除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:

            -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集.

            -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

            现在我们在 JDK 8下重新运行一下代码段 4,不过这次不再指定 PermSize 和 MaxPermSize。而是指定 MetaSpaceSize 和 MaxMetaSpaceSize的大小。输出结果如下:

    在这里插入图片描述

    5)关于为什么移除永久代?

            字符串存在永久代中,容易出现性能问题和内存溢出。
            类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。
            永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。
            Oracle 可能会将HotSpot 与 JRockit 合二为一。

    5)补充

    某种程度上说,该图也是正确的:来源:
    https://www.zhihu.com/question/300075241/answer/519570351
    在这里插入图片描述

    展开全文
  • JDK1.7的时候zhuan,方法区合并到了shu内存中,这时的常量池也可以说是在堆内存中; JDK1.8及以后,方法区又从内存中剥离出来了,但实现方式与之前的永久代不同,这时的方法区被叫做元空间,常量池就存储元...

    JDK1.6及以前,常bai量池在方法du区,这时的方法区也叫做zhi永久代dao;
    JDK1.7的时候zhuan,方法区合并到了堆shu内存中,这时的常量池也可以说是在堆内存中;
    JDK1.8及以后,方法区又从堆内存中剥离出来了,但实现方式与之前的永久代不同,这时的方法区被叫做元空间,常量池就存储在元空间。

    展开全文
  • 要是没有实践过别人书本上的理论的话,就还是会说常量池在方法区里面,要是知道方法区已经随jdk升级,被逐步干掉的话,就会看到有的文章说移动到heap里面了,还有极少的说移动到Metaspace里面了,产生了分歧。...

    要是没有实践过别人书本上的理论的话,就还是会说常量池在方法区里面,要是知道方法区已经随jdk升级,被逐步干掉的话,额,也不能说被干掉,只是被优化了,这又体现了看书的程度深浅了,就会看到有的文章说常量池移动到heap堆里面了,还有极少的说移动到Metaspace里面了,产生了分歧。这个时候就需要实践出真知了。

    /**
     * 测试 常量池在分区的位置
     *
     * @author LiXuekai on 2020/6/9
     */
    public class StringConstantPoolTest {
        public static void main(String[] args) {
            List<String> list = Lists.newArrayList();
            while (true) {
                list.add(String.valueOf(System.currentTimeMillis()).intern());
    
            }
        }
    }

    代码很简单,那本书上也大致是这个样子。String.intern()会将字符串丢到字符串常量池里面。以此来不断增加常量池的使用部分。

    还有你得一直使用着这个字符串,不然就被gc了,你就看不到oom现象了。

    jdk1.6的测试

    他当时测试的时候,出的异常是方法区OOM.

    当时的jdk还是1.6,我这就不测试1.6的了。

    执行结果说明jdk1.6的时候常量池在方法区。

    jdk1.7的测试

    下面是jdk1.7的测试情况,还是这个代码,就是启动参数设置的不一样。

    使用的jvm参数设置:

    -XX:+PrintGCDetails -Xms100M -Xmx100M -Xmn10M -XX:SurvivorRatio=8 -XX:PermSize=10m -XX:MaxPermSize=10m

    然后这个程序的异常截图如下:

    堆空间溢出。

    使用jvm看内存分区的使用情况的截图:

    可以看到堆里面old区总共90M,已经89M,这个是在报oom之前的截图。方法区总共就分了10m,在oom的时候,也就使用了7m多,说明这个常量池,在jdk1.7的时候,确实被安排到了堆Java heap里面了。

    上面的说明加起来,使得下面这个理论得到了验证。

    永久代主要存放以下数据:

    JVM internal representation of classes and their metadata //类及其元数据的JVM内部表示
    Class statics //类的静态
    Interned strings //实际字符串,说的就是常量池吧

    从 JDK7 开始,JDK 开发者们就有消灭永久代的打算了。有部分数据移到永久代之外了:

    Symbols => native memory // 符号引用 >本机内存
    Interned strings => Java Heap // Interned string => Java堆
    Class statics => Java Heap //类statics => Java堆

    结论:jdk1.7的时候,常量池已经被安排在堆里面了。

    jdk1.8的测试

    使用的jvm参数设置:

    -XX:+PrintGCDetails -Xms200M -Xmx200M -Xmn10M -XX:SurvivorRatio=8 -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:CompressedClassSpaceSize=5M

    代码执行时候报的异常截图

    使用jvm看内存分区的使用情况的截图:

    设置堆的大小是200m,元空间就只有10m,测试了几次了,每次堆的old区里面也就残留81m,看元空间的最大是10m,使用了8.4m之后,差不多就oom了。堆还差得远呢。

    说明这个常量池就是在元空间里面了吧,不能在Java heap里面了吧。

    在看元空间的时候,有个这个图

    说是开发jvm的人画的。元空间被分为2部分,类空间 class space 和非类空间 non class space

    深入 Class Space:

    最大的一部分是 Klass 结构,它是固定大小的。

    然后紧跟着两个可变大小的 vtable 和 itable,前者由类中方法的数量决定,后者由这个类所实现接口的方法数量决定。

    随后是一个 map,记录了类中引用的 Java 对象的地址,尽管该结构一般都很小,不过也是可变的。

    vtable 和 itable 通常也很小,但是对于一些巨大的类,它们也可以很大,一个有 30000 个方法的类,vtable 的大小会达到 240k,如果类派生自一个拥有 30000 个方法的接口,也是同理。但是这些都是测试案例,除了自动生成代码,你从来不会看到这样的类。

    深入 Non-Class Space

    这个区域有很多的东西,下面这些占用了最多的空间:

    • 常量池,可变大小;
    • 每个成员方法的 metadata:ConstMethod 结构,包含了好几个可变大小的内部结构,如方法字节码、局部变量表、异常表、参数信息、方法签名等;

    最后,那就按照老外的说法来吧,我的测试也稍微辅助说明一下吧,虽然代码里面报错是Java heap 溢出。这点奇怪了。

    姑且最终结论,常量池就是在Metaspace 元空间里面。

    参考:

    老外原文地址

    怎么想怎么都觉得不对,这个常量池怎么能在元空间里面。

    后面又调整参数,-xms 和-xmx设置2g,代码运行时间就更久了,说明啥,数据对象分配了那么多,要是这个方法区,早就被撑爆炸了,怎么可能会在元空间呢。这地方就分给他10,这个图上最大也就13m,肯定不可能装下那么多的字符串的。那老外画的图又作何解释呢。老外画错了,或者说老外没画明白。

    所以,最终的测试结论:

    结论:这个常量池(特指字符串常量池而不是所有的常量池),应该还是在Java heap里面,

    上面的测试只能证明:jdk1.8中 字符串常量池是在堆里面。

    JAVA的三种常量池

    此外,Java有三种常量池,即字符串常量池(又叫全局字符串池)、class文件常量池、运行时常量池

    1. 字符串常量池(也叫全局字符串池、string pool、string literal pool)

    字符串常量池   Interned Strings

    2. 运行时常量池(runtime constant pool)

    当程序运行到某个类时,class文件中的信息就会被解析到内存的方法区里的运行时常量池中。每个类都有一个运行时常量池

    3. class文件常量池(class constant pool)

    class常量池是在编译后每个class文件都有的,class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是 常量池*(constant pool table)*,用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。*字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等。

    按照这个分析的话,

    运行时常量池和静态常量池存放在元空间中,而字符串常量池依然存放在堆中。

    这个理论还说的通,但是另外2个常量池就不好测试了。

    Java Language and Virtual Machine Specifications

    上面这个是jdk的官网链接,里面不管是jdk几,里面都有Method Area方法区

    都是这么几个分区,说明这几个名字都是概念。

    顺便再上传一下他原文和网页简单翻译的图

    Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.

    方法区确实是一个概念,概念,概念。

    干掉的是永久代,而不是方法区。

    卧槽,接口还在,只是实现类变了

    最开始的实现叫PermGen,后来是PermGen + java heap 一起实现,现在叫Metaspace + Java heap 一起协调工作。

    再补充帮助理解。

    元空间并不是方法区!!!

    方法区包括类信息、常量、静态变量等,是JVM规范。 方法区是jvm规范里面的概念。

    1.7之前方法区的实现就是永久代。 1.7 把常量池和静态变量放入了堆中,也就是方法区由永久代和堆实现

    1.8 把永久代删除使用元空间,也就是方法区由元空间(类信息)和堆实现(常量池、静态变量)

    堆中包含正常对象和常量池,new String()放入堆中,String::inter会将堆中的String变量放入堆中的常量池中。

    这个解释就比较完美了。

    Each run-time constant pool is allocated from the Java Virtual Machine's method area (§2.5.4). The run-time constant pool for a class or interface is constructed when the class or interface is created (§5.3) by the Java Virtual Machine.

    这句话,可不就是说,所有的运行时常量池都是从jvm的 method area 方法区分配来的。

    所以,说常量池在方法区,是对的。因为方法区是个概念的东西。

    在jvm里面具体实现还的根据不同的jdk,实现的区的名称也不一样,前有PermGen,后有permGen + Java heap ,后再有metaspace + Java heap。

    最终结论:

    字符串常量在堆内存,类的元数据在本地内存。

    展开全文
  • Java中的栈,,方法区常量池

    万次阅读 2016-01-31 16:32:40
    出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。)  栈中的数据可以共享:  int a = 3;   int b = 3;   编译器先处理int a = 3;首先它会栈中创

     要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机。   (Sun JDK 和 Open JDK除了注释不同,代码实现基本上是一样的)

    以下说的内容都是围绕HotSpot。

     

    Stack(栈):分为VM Stack(虚拟机栈)和Native Method Stack(本地方法栈),不过HotSpot虚拟机直接把本地方法栈和虚拟机栈合二为一了。 

                      虚拟机栈: 线程私有的, 描述的是Java方法执行的内存模型,方法调用的同时创建一个栈帧(储存局部变量表,操作数栈,方法出口等等),每个方法的调用直到执行完成对应的是栈帧在虚拟机中入栈和出栈的过程。                              

    局部变量表(通常说的栈其实是栈里面的局部变量表):存放基本数据类型变量和对象的引用(所需内存在编译时期完成分配,方法运行时期不改变局部变量表大小,四个字节占用一个局部变量空间)
     

     --------栈中的数据可以共享:

                 int a = 3; 
                 int b = 3; 
       编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放 进来,然后将a指向3。接着  处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令  a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不  会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译  器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 

    包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。

    ==比较的是对象的地址,也就是是否是同一个对象;

    equal比较的是对象的值。

    int 变为Integer 时  如果值在-128~127之间  则不会创建新的integer对象 储存常量池中,这么做的目的是提高效率----->记得在别的地方看过不知道对不对


    Java代码  
    public class Test {    
        public static void main(String[] args)    
        {  int a1=1;  
            int b1=1;  
            int c1=2;  
            int d1=a1+b1;  
            Integer a = 1;    
            Integer b = 2;    
            Integer c = 3;    
            Integer d = 3;    
            Integer e = 321;    
            Integer f = 321;    
            Long g = 3L;    
            System.out.println(a1==b1);   //true  结果1    
            System.out.println(c1==d1);   //true  结果2  
            System.out.println(c==d);   //true  结果3     
            System.out.println(e==f);   //false  结果4       
        }    
    }    
     分析:结果1:a1==b1如上面所述,会在栈 中开辟存储空间存放数据。
              结果2:首先它会在栈 中创建一个变量为c1的引用,然后查找有没有字面值为2的地址,没找到,就开辟一个存放2这个字面值的地址,然后将c1指向2的地址,d1为两个字面值相加也为2, 由于在栈中已经有2这个字面值,便将d1直接指向2的地址。这样,就出现了c1与d1同时均指向3的情况。
     
            在分析下面结果以前让我们先对Java自动拆箱和装箱做个了结:在自动装箱时,把int变成Integer的时候,是有规则的,当你的int的值在-128-IntegerCache.high(127) 时,返回的不是一个新new出来的Integer对象,而是一个已经缓存在堆 中的Integer对象,(我们可以这样理解,系统已经把-128到127之 间的Integer缓存到一个Integer数组中去了,如果你要把一个int变成一个Integer对象,首先去缓存中找,找到的话直接返回引用给你就 行了,不必再新new一个),如果不在-128-IntegerCache.high(127) 时会返回一个新new出来的Integer对象。
     
             结果3:由于3是在范围内所以是从缓存中取数据的,c和d指向同一个对象,结果为true;
             结果4:由于321不是在范围内所以不是从缓存中取数据的而是单独有new对象,e和f并没有指向同一个对象,结果为false;

    JAVA堆:

    Java堆是被所有线程共享的一块区域,在虚拟机启动时创建 ,此内存的唯一目的就是存放对象实例和数组   GC 管理的主要区域。

    分为新生代(Eden Survivor Survivor8:1:1)和老年代

    Java堆可以处于物理上不连续的内存空间中,只要逻辑连续即可

    关于对象的创建请参考:http://note.youdao.com/yws/public/redirect/share?id=5177014ee5ad1ac3f0af9fdab3b011a3&type=false
    关于GC回收请参考:http://note.youdao.com/yws/public/redirect/share?id=96928e82082b4dec8831e5099769172b&type=false

     

    方法区:

                不等价于永久代hotspot用永久代实现方法区( 在jdk1.7的HotSpot中 已经把原本放在永久代中的字符串常量池移出
                  与堆一样是线程共享的一块内存区域
                  用于储存已被虚拟机加载的信息、常量、静态变量、即时编译器编译后的代码等数据。
                 垃圾收集行为在方法区很少出现,这块区域回收的主要目标是针对常量池的回收和对类型的卸载            

     

    运行时常量池:

                           方法区的一部分
                            常量池用于存放编译期生成的各种 字面量符号引用(还有翻译出来的直接引用),这部分内容在类加载后进入方法区的运行时常量池中存放。 
                           运行时常量池相对于Class文件常量池的另一个重要特征是具备动态性,运行期间也可能将新的常量放入池中

                 字面量:如文本字符串,声明为final的常量值等。

                                           public stick final int i =3;

                                                        String s="abc";

                     符号引用:类和接口的全限定名 

                                              字段的名称和描述符

                                    方法的名称和描述符

     

    String 的本质是字符数组。 
    String 的标准实现含有4个实例变量 
                                            指向字符数组的引用       
                                            int类型    偏移量
                                            int类型    字符串的长度
                                            int类型     散列值

    public class String{
          private char[]value;
          private int offset;
          private int count;
          private int hash;
    ...
    }

    一个String对象总共使用40字节(16字节对象本身开销+8字节的引用+三个int类型(12字节)+4字节(填充字节)),因为String的char数组常常是在多个字符串之间共享的,因此String对象是不可变的
     

    String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建

    String str = "abc"创建对象的过程
    1 首先在常量池中查找是否存在内容为"abc"字符串对象
    2 如果不存在则在常量池中创建"abc",并让str引用该对象
    3 如果存在则直接让str引用该对象


    至 于"abc"是怎么保存,保存在哪?常量池属于类信息的一部分,而类信息反映到JVM内存模型中是对应存在于JVM内存模型的方法区,也就是说这个类信息 中的常量池概念是存在于在方法区中,而方法区是在JVM内存模型中的堆中由JVM来分配的,所以"abc"可以说存在于堆中(而有些资料,为了把方法区的 堆区别于JVM的堆,把方法区称为栈)。一般这种情况下,"abc"在编译时就被写入字节码中,所以class被加载时,JVM就为"abc"在常量池中 分配内存,所以和静态区差不多。
    4(2)String str = new String("abc")创建实例的过程
    1 首先在堆中(不是常量池)创建一个指定的对象"abc",并让str引用指向该对象
    2 在字符串常量池中查看,是否存在内容为"abc"字符串对象
    3 若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来
    4 若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象,并将堆中的对象与之联系起来

    String str1 = "abc"; String str2 = "ab" + "c"; str1==str2是ture
    是因为String str2 = "ab" + "c"会查找常量池中时候存在内容为"abc"字符串对象,如存在则直接让str2引用该对象,显然String str1 = "abc"的时候,上面说了,会在常量池中创建"abc"对象,所以str1引用该对象,str2也引用该对象,所以str1==str2
    String str1 = "abc"; String str2 = "ab"; String str3 = str2 + "c"; str1==str3是false                ---------//可参考Java编程思想第四版P284,285
    是因为String str3 = str2 + "c"涉及到变量(不全是常量)的相加,所以会生成新的对象,其内部实现是先new一个StringBuilder,然后 append(str2),append("c");然后让str3引用toString()返回的对象

     

     

     

        String s = new String(“abc”); 产生几个对象?

        一个或两个,如果常量池中原来没有 ”abc”, 就是两个(参考栈中的数据共享)。

     



    展开全文
  • Heap 的定义 定义 :通过 new 关键字,创建对象都会使用内存 特点 它是线程共享的,中对象都需要考虑线程安全的问题 有垃圾回收机制 内存溢出 使用下面代码进行演示 import java.util.ArrayList; import ...
  • JDK1.7 及之后版本的 JVM 已经将运行时常量池方法区中移了出来, Java (Heap)中开辟了一块区域存放运行时常量池。 JDK1.8开始,取消了Java方法区,取而代之的是位于直接内存的元空间(metaSpace)。 已知:...
  • String.intern()方法的作用是返回一个字符串引用,引用的是字符串常量池中的字符串(字面量),所以我们可以通过这个方法来测试,使得字符串常量池内存溢出,看看这个时候报错报的是哪里out of memory。 import ...
  • 本次测试的JDK版本为: ...public class 验证字符串常量池在堆中 { public static void main(String[] args) { //保持对象引用,防止被GC Set<String> set = new HashSet<String>(); long i = 0; .
  • 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。); 静态域:存放静态成员(static定义的...
  • java栈,函数的定义中定义的基本类型(int,long,short,byte,float,double,boolean,char)的变量数据和对象的引用变量分配的存储空间的地方。当代码块中定义一个变量时,java栈就为这个变量分配适当的内存空间,...
  • 理解归纳方法区常量池

    千次阅读 2018-05-12 15:31:34
     我对方法区的理解其实是个逻辑区,其是哪里不重要,在堆内外都没关系,对于HotSpot来说,方法区JDK1.7是永久代,而1.8元空间(与不相连的本地内存)。 而常量池方法区的一部分(说的不是很准备)1. ...
  • 给一个字符串变量赋值有两种方式: String str1=new String("This is a string"); String str2 ="This is a string"; 第一种方式通过关键字new定义:先字符串常量区查找是否存在...然后在堆区,开辟一个空间,存放
  • 小菜先拙劣的表达一下jvm虚拟内存分布: 程序计数器是jvm执行程序的流水线,存放一些跳转... 方法区存放了一些常量、静态变量、类信息等,可以理解成class文件内存中的存放位置。 虚拟机是jvm执行jav...
  • java方法区常量池

    千次阅读 2018-07-04 17:55:11
     class文件中除了包含类的版本,类名,字段,方法,接口等信息,还包含了常量池,这里面存放了编译期产生的各种 字面量以及符号引用,类加载后进入方法区的运行时常量池中,运行时常量池相对于class常...
  • String实质是字符数组,两个特点:1、... 第一种方式通过关键字new定义过程:程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果...
  • 方法区常量池

    万次阅读 多人点赞 2017-11-15 21:20:11
    最近一直被方法区里面存着什么东西困扰着?  1.方法区里存class文件信息和class文件常量池是个什么关系。  2.class文件常量池和运行时常量池是什么关系。    方法区存着类的信息,常量和静态变量,即类被编译后...
  • JDK8以前,很多把方法区和永久代混为一谈,本质上这两者并不是等价的,仅仅是因为当时的HotSpot虚拟机设计团队选择吧收集器的分代设计扩展至方法区,或者说使用永久代来实现方法区而已,这样使得HotSpot的垃圾收集...
  • 主要介绍了通过String.intern()方法浅谈常量池JDK7之前,字符串常量是存在永久带Perm 的,JDK7开始常量池迁移到中,这个变化也导致了String的新特性,下面我们慢慢进行介绍。,需要的朋友可以参考下
  • Java常量池方法区

    2020-01-11 20:29:53
    JDK1.8后方法区内存结构的变化 2、添加链接描述 3、添加链接描述 4、添加链接描述 从字节码分析了JDK7中常量放到中后的 内存结构 1、运行时数据区域 Java虚拟机执行Java程序的过程中会把它所管理的内存划分为...
  • 中对象中有一个类型指针是对方法区中类元信息的引用。 对象中的实例具体的数据中可能就会有对字符串常量池的引用。常量池中存储这一系列字符串数据。 一个对象还可以指向另一个对象。 另外想了解 对象头 的内部...
  • 详细的总结了java中内存中创建的、栈、方法区常量池的区别和用途
  • 方法区是各个线程共享的内存区域,它存储每个类的结构信息,例如运行时常量池,字段(通过引用常量池中的常量来描述)和方法等数据,以及方法和构造函数的代码,包括用于类和实例初始化以及接口初始化的特殊方法。...
  • 常量池方法区栈与队列 Java 中,下面关于String 类和StringBuffer 类的描述正确的是哪一个 a. StringBuffer 类的对象调用toString()方法将转化为String 类型 b. 两个类都有append()方法 c. 可以直接将...
  • 、栈和常量池的比较

    千次阅读 2018-08-06 09:11:11
    1.寄存器:最快的存储,位于不同于其他存储的地方——处理器内部。寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能程序中感觉到寄存器存在的任何迹象。 2. 栈:存放基本...
  • 方法区(落地实现jdk7永久代,jdk8元空间),元空间并不...jdk1.7 存在永久代,字符串常量池被移动到了当中,运行时常量池还是在永久代中; jdk1.8 不存在永久代,实现形式是元空间,字符串常量池仍然在堆当中,运行.
  • 转自:http://www.cnblogs.com/protected/p/6419217.html程序运行时,有六个地方都可以保存数据:...我们对此没有直接的控制权,也不可能自己的程序里找到寄存器存在的任何踪迹。 2、 堆栈:存放基本类型的数据和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,554
精华内容 30,221
关键字:

常量池在堆还是方法区