2024年10月字符串常量池和运行时常量池(Java构造函数(方法)存储在jvm哪个内存里)

 更新时间:2024-10-12

  ⑴字符串常量池和运行时常量池(Java构造函数(方法存储在jvm哪个内存里

  ⑵Java构造函数(方法存储在jvm哪个内存里

  ⑶存放到方法区当中;new出来的是实例对象,实例对象才是存放在堆当中;构造函数对应的是《init》方法,方法信息随着类加载器加载到方法区当中。栈:以栈帧为单位,存放的不是方法具体的结构,只是通常一个方法对应一个栈帧,对应的入栈出栈就是栈帧的入栈出栈。栈帧中有局部变量表,操作数栈,方法返回地址,动态链接。其中局部变量表存放局部变量,包括形参,非静态方法默认在第一个索引存放一个this变量;操作数栈用于操作局部变量表和一些值的运算,比如读取表中变量的值进行运算,或存放相应的值到局部变量表中;方法返回地址则是用于记录对应方法的下一条指令的地址;动态链接是符号引用变成的直接引用。堆:存放实例对象,在jdk开始,还存放静态变量和字符串常量池方法区:存放类元信息,比如完整类名全称,public,abstract等修饰符,实现的接口有序列表等;方法信息,比如修饰符,返回类型等;JIT代码缓存,也就是被即时编译器编译后的热点代码,用于提高性能;域信息,也就是属性信息,比如修饰符,类型等;运行时常量池,字节码文件中常量池的运行时表现,类似符号引用的记录,不过蕴含的信息更为丰富,而且具有动态性。jdk及以前,还存放静态变量,运行时常量池中还存放字符串常量池,到了jdk则移到了堆中。

  ⑷JVM中常量池存放在哪里

  ⑸java之前:java之后:元数据区Metaspace由于PermGen内存管理的效果远没有达到预期,所以JCP已经着手去除PermGen的工作。在JDK中,字符串常量已经从永久代移除。现今JDK中PermGen已经被彻底移除,取而代之的是metaspace数据区,使用native内存,申请和释放由虚拟机负责管理。那么,JVM中常量池到底存放在哪里?Java和之前,常量池是存放在方法区(永久代中的。Java,将常量池是存放到了堆中。Java之后,取消了整个永久代区域,取而代之的是元空间。运行时常量池和静态常量池存放在元空间中,而字符串常量池依然存放在堆中。

  ⑹字符串常量池在堆中还是方法区

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

  ⑻字符串常量池到底存放的是字符串引用还是字符串对象

  ⑼你看看String源码就明白了,是对象!s=““;写这句话的时候,会在常量池先找有没有这个字符串对象如果没有,他就开始抽取,,,然后拼接成一个对象即:““;假如后面又来一个也需要这个对象,比如说s=““;这个时候在操作s的时候还是先去常量池找有没有这个对象,如果有,直接把地址拿过来,因为常量池数据为共享的,假如这个时候s=““;那么常量池是没有的,就会重新抽取,,,,,然后重新拼接成一个新的对象放在常量池!String源码里面有一个私有变量一个字符类型的数组,他就是用来抽取这些单个字符,然后拼接成一个字符串对象!

  ⑽Java中的几种常量池

  ⑾字符串的常量池和字符串池是一样的吗

  ⑿不是一个东西,常量池必须是字符串初始化的,字符串是对象,在方法区存储,在heap上开空间存储

  ⒀JDK.、JDK.、JDK.内存模型对比

  ⒁如图-是JDK.、.、.的内存模型演变过程,其实这个内存模型就是JVM运行时数据区依照JVM虚拟机规范的具体实现过程。JDK.:程序计数器、Java虚拟机栈、本地方法栈、堆、方法区(字符串常量池、静态变量、运行时常量池、类常量池JDK.:程序计数器、Java虚拟机栈、本地方法栈、堆(字符串常量、静态变量、方法区(运行时常量池、类常量池JDK.:程序计数器、Java虚拟机栈、本地方法栈、堆(字符串常量、元数据(静态变量、运行时常量池、类常量池JDK.JVM的内存结构主要由三大块组成:堆内存、元空间和栈,Java堆是内存空间占据最大的一块区域。Java堆,由年轻代和年老代组成,分别占据/和/。年轻代又分为三部分,Eden、FromSurvivor、ToSurvivor,占据比例为::,可调。元空间从虚拟机Java堆中转移到本地内存,默认情况下,元空间的大小仅受本地内存的限制,说白了也就是以后不会因为永久代空间不够而抛出OOM异常出现了。jdk.以前版本的class和JAR包数据存储在PermGen下面,PermGen大小是固定的,而且项目之间无法共用,公有的class,所以比较容易出现OOM异常。升级JDK.后,元空间配置参数,-XX:MetaspaceSize=MXX:MaxMetaspaceSize=M。小技巧通过jps、jinfo查看元空间,如下:通过jinfo查看默认MetaspaceSize大小(约M,MaxMetaspaceSize比较大。其他:关于JDK.元空间的介绍:?MovepartofthecontentsofthepermanentgenerationinHotspottotheJavaheapandtheremaindertonativememory.

  ⒂什么叫做字符串常量池

  ⒃可以理解为内存里面专门为string类型变量开辟的一片区域譬如Stringa=“abc“;当你定义这样一个变量的时候,java此时先会去常量池寻找有没有“abc“这样的字符串,如果有,直接把内存地址交给a,否则就生成一个“abc“的字符串当下一个Stringb=“abc“;的时候,发现常量池已经有“abc“了,此时JVM不会再次生成“abc“,而是直接交给“abc“引用给b,所以此时你会发现a==b

  ⒄jvm的内存模型中运行时常量池与Class文件结构中说的常量池是否是同一个

  ⒅老年代调整:标记-清除(Mark-Sweep)算法标记-压缩(Mark-pact)算法老年代调整参数:-XX:PretenureSizeThreshold控制直接升入老年代的对象大小,大于这个值的对象会直接分配在老年代中FULLGC发生的概率比较低,发生的话操作时间特别长,严重影响程序的性能。永久代(JDK.之后被废除了该区域中的对象不会被回收。当时简单的理解是方法区就是永久代,HotSpot虚拟机规范中是存在永久代概念的。被元空间取代JDK.之后,元空间取代永久代,元空间的本质就是本机的物理内存OOM异常可能分为堆内存溢出(JavaHeapspace:往往出现在FUllGC失败之后永久代溢出(PermGenspace:一个方法中出现的内存溢出元空间溢出(Metaspace:分配的物理内存不足,或者数据量高于物理内存垃圾的收集一定要分两个空间考虑:年轻代、老年代,老年代的内存空间要大于年轻待可用GC方式:新生代可用GC策略:串行GC(SerialCopying)并行回收GC(ParallelScavenge):复制(Copying)清理算法;操作步骤:在扫描和复制时均采用多线程方式处理,并行回收GC为空间较大的年轻代回收提供许多优化优势:在多CPU的机器上其GC耗时会比串行方式短,适合多CPU、对暂停时间要求较短的应用并行GC(ParNew):复制(Copying)清理算法操作步骤:并行GC(ParNew)必须结合老年代,“CMSGC“一起使用。因为年轻代如果发生了“MinC“时,老年代也需要使用“CMSGC“同时处理,(并行回收GC并不会做这些CMS(ConcurrentMark-Sweep):是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适用老年代可用GC策略:串行GC(SerialMSC)算法:标记-清除-压缩(Mark-Sweep-pact操作步骤:扫描老年代中还存活的对象,并且对这些对象进行标记遍历整个老年代的内存空间,回收所有未标记的对象内存将所有存活对象都集中在一端,而后将所有回收对象的内存空间变为一块连续的内存空间优缺点:串行执行的过程中为单线程,需要暂停应用并耗时较长并行GC(ParallelMSC)算法:标记-压缩(Mark-pact操作步骤:将老年代内存空间按照线程个数划分若干子区域;多个线程并行对各自子区域内的存活对象进行标记多个线程并行清除所有未标记的对象多个线程并行将多个存活对象整理在一起,并将所有被回收的对象空间整合为一体优缺点:多个线程同时进行垃圾回收可以缩短应用的暂停时间,但是由于老年代的空间一般较大,所以在扫描和标记存活对象上需要花费较长时间。与串行相比,就是多了一个多线程的支持,但是这样的暂停时间就会减少并行GC(CMS)算法:标记-清除(Mark-Sweep操作步骤:初始标记(STW【Stop-TheWorld】InitialMark:虚拟机暂停正在执行的任务(STW,由根对象扫描出所有的关联对象,并做出标记。此过程只会导致短暂的JVM暂停并发标记(ConcurrentMarking:恢复所有暂停的线程对象,并且对之前标记过的对象进行扫描,取得所有跟标记对象有关联的对象并发预处理(ConcurrentPrecleaning:查找所有在并发标记阶段新进入老年代的对象(一些对象可能从新生代晋升到老年代,或者有一些对象被分配到老年代,通过重新扫描,减少下一阶段的工作重新标记(STWRemark:此阶段会暂停虚拟机,对在“并发标记”阶段被改变引用或新创建的对象进行标记并发清理(ConcurrentSweeping:恢复所有暂停的应用线程,对所有未标记的垃圾对象进行清理,并且会尽量将已回收对象的空间重新拼凑为一个整体。在此阶段收集器线程和应用程序线程并发执行并发重置(ConcurrentReset:重置CMS收集器的数据结构,等待下一次垃圾回收。优缺点:只有在第一次和重新标记阶段才会暂停整个应用,这样对应用程序所带来的影响非常的小、缺点是并发标记与回收线程会与应用线程争抢CPU资源,并且容易产生内存碎片。常用GC策略:运行环境年轻代GC老年代单机程序(client串行GC(SerialCopying)串行GC(SerialMSC)服务器程序(Server并行回收GC(ParallelScavenge)并行GC(ParallelMarkSweep、Parallelpacting)如果要向确认使用的GC处理,首先需要知道当前的主机上可以支持的处理进程数量调参:使用串行GC策略:-XX:+UseSerialGC使用并行GC策略:-XX:+UseParNewGC使用CMS:-XX:+UseConcMarkSweepGMS会经历如下几个步骤:“CMS-concurrent-mark-start“:CMS标记开始“CMS-concurrent-mark“:表示开始进行标记,进入到了STW状态(暂停“CMS-concurrent-preclean-start“:预清理开始“CMS-concurrent-sweep-start“:开始进行无用对象清理CMS的处理适当性能会好一些,但是这所有的GC策略都是现在正在常用的策略,不过似乎都有缺陷。总结:实际开发之中对于GC的策略不建议手动修改,默认的一版比较好G收集器:对Java服务器而言,如何去选择一个合适的配置呢?默认情况下,Java会为每一个线程分配M的内存空间。如果现在电脑有G的内存,最大可以分配G的内存空间(理论理论上可以处理*个用户请求,所以一般的服务器处理个——基本上也就够了G的实现方案相当于将所有的子内存区域合并在一起,也不在进行任何的区分,这样就相当于所有的内存的区域都可以按照统一的方式进行统一规划处理G的最大特点就是避免了全内存扫描G在标记和清理的时候是按照区域完成的,这样不影响其他的区域的执行,除此之外,使用的形式和之前的CMS都是类似的操作方式。调参使用G收集器:-Xmxm-Xmsm-XX:+PrintGCDetails-XX:+UseGGCG的垃圾收集比传统的GC要快一些引用类型概述:对于垃圾的产生与回收的处理之中,要想进行更好的控制,就必须清楚的掌握JAVA中的四种引用方式:.强引用(StrongReference:即使进行了多次GC的回收,即使JVM的内存真的已经不够用了,最终不得以抛出了OOM错误,那么该引用继续抢占.软引用(SoftReference:当内存空间不足时,可以回收此内存空间。如果充足则不回收,可以用其完成一些缓存的处理操作开发.弱引用(WeakReference:不管内存是否紧张,只要一出现GC处理,则立即回收.幽灵引用(PhantomReference:和没有引用是一样的强引用:即使出现GC,即使内存不足,该引用的数据也不会被回收强引用不是造成OOM的关键因素,正常来讲,你每一个用户(线程操作完成后该对象都很容易进行回收。软引用:当内存空间不足时才进行GC的空间释放,但是如果想使用软引用必须单独使用特殊的处理类:importjava.lang.ref.SoftReference;publilassSoftReferenceTest{publicstaticvoidmain(Stringargs){Stringstr=“加入到软引用之中SoftReference《String》stringReference=newSoftReference《String》(str);//类似强引用端口连接str=null;//因为软引用空间还很富裕,所以不会释放System.gc();System.out.println(stringReference.get());}}在开发中,可以利用软引用实现高速缓存组件弱引用:最大的特点:一旦发生GC操作,则保存的内容则立即释放importjava.lang.ref.WeakReference;publilassWeakReferenceTest{publicstaticvoidmain(Stringargs){Stringa=newString(“);WeakReferencereference=newWeakReference《String》(a);a=null;System.gc();System.out.println(reference.get());}}在我们类集里面有一个与弱引用功能相似的Map集合,WeakHashMap《K,V》,它属于弱引用的一个实现importjava.util.*;publilassWeakReferenceTest{publicstaticvoidmain(Stringargs){Map《Integer,String》map=newWeakHashMap《Integer,String》();map.put(newInteger(),newString(“a“));map.put(newInteger(),newString(“b“));System.gc();System.out.println(map);}}使用WeakHashMap好处是保存一些共享数据,如果长时间不使用则可以清空引用队列:如果要想清楚引用队列,则首先必须知道对象的引用的强度,如果说按照现在的理解来讲:强引用》软引用》弱引用。引用队列里面所保存的就是一个要准备被回收的对象的信息importjava.lang.ref.Reference;importjava.lang.ref.ReferenceQueue;importjava.lang.ref.WeakReference;publilassReferenceQueueTest{publicstaticvoidmain(Stringargs)throwsException{Stringstr=newString(“);ReferenceQueue《String》queue=newReferenceQueue《String》();WeakReference《String》weak=newWeakReference《String》(str,queue);str=null;System.out.println(weak.isEnqueued());System.gc();Thread.sleep();System.out.println(weak.isEnqueued());//观察队列是否有内容System.out.println(queue.poll());}}幽灵引用(虚引用:幽灵引用指的是什么都不保存,但是又看起来保存了似得。importjava.lang.ref.PhantomReference;importjava.lang.ref.ReferenceQueue;publilassPhantomReferenceTest{publicstaticvoidmain(Stringargs)throwsException{Stringstr=newString(“);ReferenceQueue《String》queue=newReferenceQueue《String》();PhantomReference《String》ps=newPhantomReference《String》(str,queue);str=null;System.out.println(ps.isEnqueued());System.gc();Thread.sleep();System.out.println(ps.isEnqueued());//观察队列是否有内容System.out.println(queue.poll());}}幽灵引用直接把保存的内容保存在引用队列之中关于逃逸分析:在平时开发过程中就要可尽可能的控制变量的作用范围了,变量范围越小越好建议去刷题,我运气好,简单的算法让我碰到了,一些快排,堆排,二叉树相关的,链表反转,成环,环节点,跳楼梯等常规的简单算法建议刷刷,双指针,dp,递归这些还是多找找感觉,大数据内存有限的场景的统计,有时间一些middle可以去试试,手写红黑树你要是可以,那我估计算法你稳了堆栈相关:.寄存器:最快的存储区,由编译器根据需求进行分配,我们在程序中无法控制..栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new出来的对象或者常量池中(字符串常量对象存放在常量池中。.堆:存放所有new出来的对象。.静态域:存放静态成员(static定义的.常量池:存放字符串常量和基本类型常量(publicstaticfinal。.非RAM存储:硬盘等永久存储空间

您可能感兴趣的文章:

相关文章