Java虚拟机(JVM)学习笔记(不定时更新)
Java虚拟机(JVM)学习笔记
不少组织都曾开发过Java虚拟机:
SUN公司曾经使用过3个虚拟机,Classic、Exact VM、Hotspot。
其中Hotspot虚拟机沿用至今,并已被Oracle合并到其新的虚拟机平台中(与同样被Oracle收购的BEA公司的JRocket虚拟机合并)。
IBM的Java虚拟机叫J9。
Apache也曾推出过一款叫做Apache Harmony的Java运行平台,受到同样开源的OpenJDK的排挤,已于2011年退出市场。
Java虚拟机的基本结构:
1、类加载子系统;
2、Java内存(程序计数器、Java堆、Java栈、本地方法栈、方法区、直接内存);
3、垃圾回收子系统;
4、执行引擎。
Java堆:
一个Java程序的几乎所有对象都存放在堆中,并且堆是完全自动化管理的,不需要显式释放堆中的垃圾对象。
在不同的虚拟机中或在不同的垃圾回收机制下,Java堆可能具有不同的结构特征,但最常见的组织结构是把整个堆分为新生代和老年代(tenured)。
新生代中存放新创建的对象和“年龄”不大的对象;老年代则存放“年龄”足够大的对象。
新生代又分为eden、from、to三个区域,其中from和to是两块大小相等、可以互换角色的内存空间。
通常,新创建的对象在eden区分配内存,在一次新生代回收后,如果对象还存活,则会被转移到from区或to区。
对象进入from区或to区之后,没经过一次新生代回收,如果对象还存活着,则它的“年龄”加1。当“年龄”增长到一定程度后,会被转移到老年代。
Java栈:
Java栈是线程私有的内存空间。函数调用是线程执行的基本行为,每次函数调用所需的数据都是通过Java栈传递的。
Java栈和数据结构课程中所描述的栈有类似的特征,都是一种先进后出的数据结构,只支持入栈和出栈两种操作。
栈帧是Java栈的基本单元。每次函数调用都会有一个栈帧入栈;每次函数调用结束,都会有一个栈帧出栈。
无论函数是正常返回还是抛出异常,都会有一个栈帧出栈。
栈帧:
在一个栈帧中,至少包含3个部分:局部变量表、操作数栈、帧数据区。
由于每次函数调用都会有栈帧入栈,从而占据更多的栈空间,显然如果栈空间不足以放置更多的栈帧时,函数调用将无法继续下去,这个时候会抛出StackOverflowError。
Java虚拟机提供了“-Xss”参数,用于在虚拟机启动的时候配置栈空间的最大值,这个最大值决定了函数嵌套调用的深度。
局部变量表:
局部变量表是栈帧的重要组成部分,它用于保存函数的参数和局部变量。
由于局部变量表在栈帧中,如果函数的参数和局部变量过多,会造成局部变量表膨胀,从而栈帧变大,函数嵌套调用的深度也会降低。
操作数栈:
操作数栈也是栈帧的组成部分之一,它被用来保存计算的中间结果,作为计算过程中变量的临时存储空间。
操作数栈也是先进后出的,很多Java字节码指令都需要通过操作数栈进行参数传递。
帧数据区:
帧数据区中保存着常量池的指针,方便字节码指令访问常量池。
帧数据区中保存了一张异常处理表,方便在发生异常时找到处理异常的代码。
栈上分配:
栈上分配是Java虚拟机提供的优化技术。
它的思路是,可以把某些线程私有对象分配在栈上,借助退栈操作直接清理该对象,而不需要垃圾回收子系统的介入,减少GC,从而提高系统性能。
栈上分配的技术基础是逃逸分析,逃逸分析用于判断某个对象是否能够被其他线程访问到。
如果某个对象能够被其他线程访问到,则它是一个逃逸对象,不能分配在栈上。
顺便提一下,书上说只有Java虚拟机运行在Server模式下的时候,才可以启用逃逸分析。
方法区:
方法区和Java堆一样,是线程共享的内存区域。它主要用于保存Java类信息(字段、方法等)。
方法区的大小决定了虚拟机中可以加载多少Java类。
如果有太多的Java类需要加载(通常使用了某些动态代理技术时,会动态产生过多的类信息),会抛出内存溢出错误。
虚拟机参数-XX:PermSize和-XX:MaxPermSize用于指定方法区的最小和最大尺寸。默认情况下,最大64MB。
在JDK1.6和1.7中,方法区也叫永久区。
在JDK1.8、1.9和1.10中,永久区已被“元数据区”取代!
元数据区是直接内存。
和永久区不同的是,元数据区可以扩展至耗尽所有系统内存。
跟踪调试参数:
Java虚拟机提供了大量用于跟踪系统状态的参数,配置使用这些参数,可以在Java程序运行过程中打印相关日志,用于问题分析。
GC参数:
GC(垃圾回收)机制是Java的一大特色,可以帮助程序员管理内存。
但是当GC对程序本身造成影响(GC过于频繁、CPU过载等)时,需要进行分析处理。
打印GC日志:
-XX:PrintGC,使用这个参数启动虚拟机,只要遇到GC,就会打印日志。
-Xlog:gc,这个参数是用来给JDK9和JDK10打印GC日志的,因为这两个版本的JDK默认使用G1收集器。
打印详细GC日志的参数是-XX:PrintGCDetails(JDK9和JDK10中对应的参数是-Xlog:gc*)。
跟踪类的加载、卸载:
-verbose:class参数可以跟踪类的加载和卸载。
单独使用-XX:+TraceClassLoading参数(JDK9和JDK10中对应的参数是-Xlog:class+load=info),跟踪类的加载情况。
单独使用-XX:+TraceClassUnloading参数(JDK9和JDK10中对应的参数是-Xlog:class+unload=info),跟踪类的卸载情况。
查看系统参数:
-XX:+PrintVMOptions参数,在程序运行时打印虚拟机接收到的命令行显式参数列表。
-XX:+PrintCommandLineFlags参数,打印传递给虚拟机的显式和隐式参数。
-XX:+PrintFlagsFinal参数,打印所有的系统参数值。
Java堆大小设置:
当Java进程启动时,虚拟机会给该进程分配一块初始堆空间,当初始堆空间耗尽后,虚拟机会扩展堆空间,扩展后的堆空间大小不能超过最大堆空间。
-Xms参数:在Java进程启动时,指定初始堆空间大小。
-Xmx参数:指定最大堆空间大小。
新生代的配置:
-Xmn参数:用于设置新生代的大小。
-XX:SurvivorRatio参数用于指定新生代中eden区和from/to区的比例,即:
-XX:SurvivorRatio=eden/from=eden/to
新生代的大小一般设置为整个堆空间的四分之一到三分之一,新生代的大小对GC有很大影响!
基本上,应该尽可能将对象预留在新生代,以减少老年代GC的次数。
设置较大的新生代会减小老年的大小。
-Xmn参数可以指定新生代的绝对大小,还可以使用-XX:NewRatio参数来设置新生代和老年代的比例:
-XX:NewRatio=老年代/新生代
堆溢出:
Java程序在运行过程中,如果遇到堆内存不足的情况时,则会抛出内存溢出错误(OOM,Out Of Memory)。
对于OOM,Java虚拟机提供了-XX:+HeapDumpOnOutOfMemoryError参数,用于在发生OOM时导出整个堆信息。
这个参数配合另一个参数-XX:HeapDumpPath,指定导出堆的存放路径:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/java.dump ...
另外,还有一个参数-XX:OnOutOfMemoryError,在发生错误时,调用一个脚本文件,用于善后处理。
java -XX:OnOutOfMemoryError=d:/abc.bat ...
方法区配置:
在JDK1.6和JDK1.7中,可以使用下面两个参数设置方法区大小的下限和上限:
-XX:PermSize
-XX:MaxPermSize
JDK1.8以后,方法区已被废弃,类信息存放在元数据区中。
元数据区只受系统可用内存的限制。
可以使用-XX:MaxMetaspaceSize参数设置元数据区的最大可用值。
直接内存配置:
直接内存跳过Java堆,直接操作系统原生内存。从一定程度上加快了内存的访问速度。
但是认为使用直接内存一定可以提高性能是错误的。
一般来说,直接内存的访问速度比Java堆内存要快,但是在内存申请时,直接内存毫无优势可言。
所以看,直接内存适合申请次数较少、访问较频繁的场景。
-XX:MaxDirectMemorySize参数可以限定直接内存的最大值,如果不设置这个参数,则默认最大值为-Xmx参数的值。
当已使用的直接内存到达指定的最大值时,会触发GC,GC后如果仍旧内存不足,会引起OOM。
Java虚拟机的工作模式:
Java虚拟机支持Client和Server两种运行模式。
这两种运行模式可以通过两个参数分别指定:
-client参数
-server参数
因为以Server模式启动Java程序时,会尝试手机更多的系统性能信息,使用更复杂的优化算法,所以Server模式启动程序的速度要慢于Client模式。
但是也正是因为这样,以Server模式启动的Java程序,要远远快于以Client模式启动的Java程序。
常见垃圾回收算法:
1、引用计数法(Reference Counting);
2、标记清除法(Mark-Sweep);
3、复制算法(Copying);
4、标记压缩法(Mark-Compact);
5、分代算法(Generationall Collecting);
6、分区算法(Region)。
引用计数法:
引用计数法是最经典且古老的一种垃圾收集算法。
引用计数法的基本思想是给对象设置一个引用次数的变量。
对象被赋值给其他变量,引用次数加一;引用失效后,引用次数减一。
但引用次数变成零的时候,代表对象不再被任何变量引用,可以直接回收该对象占用的内存空间。
引用计数法的最严重问题是无法处理循环引用的问题。
标记清除法:
标记清除法是现代垃圾收集算法的思想基础。
标记清除法分两个阶段:标记阶段和清除阶段。
在标记阶段,算法通过根节点标记所有从根节点开始的可达对象。
在清除阶段,回收所有未被标记的对象所占用的内存空间。
标记清除法的最大问题是可能产生大量的内存碎片。
复制算法:
复制算法的核心思想是:
将这个内存空间分成两块,每次只使用其中的一块。
当需要垃圾回收时,将正在使用的那一块中所有的存活对象都复制到另一块内存空间中,然后清理当前内存块中的所有对象。
之后交换两块内存的角色,GC完成。
复制算法非常符合新生代垃圾回收的要求,因为新生代里的垃圾对象通常远远多于存活对象,因此更有效率。
之前介绍过新生代被分成了三块:eden、from、to。
其中的from区和to区可以视为复制算法中的两块大小相同、地位相等且可以互换角色的内存空间。
标记压缩法:
标记压缩法是一种老年代的回收算法。
它是标记清除法的优化版。
标记压缩法在执行了标记清除法的两个阶段后,还会把存活对象压缩到内存的一端,从而避免了碎片的产生。
也就是说,标记压缩法=标记清除法+碎片整理。
分代算法:
分代算法本身并不是一种新的垃圾回收算法。
它的思路是,根据对象的特点,把内存分成不同的块,然后根据每块内存中对象的特点,选择不同的垃圾回收算法,以提高效率。
分代算法被现代虚拟机广泛使用,几乎所有的垃圾回收器都区分新生代和老年代。
通常,新生代会频繁发生垃圾回收,但是每次垃圾回收耗时都比较短;而老年代的垃圾回收并不频繁,但是只要发生垃圾回收,都会消耗很长时间。
分区算法:
通常,内存空间越大,一次垃圾回收的耗时就越长。
分区算法的思路是,把这个内存空间分割成若干小的区间,每次需要垃圾回收时,都选择其中的部分小区间进行回收,而不是回收整个内存空间。
这样就有效控制了每次垃圾回收所产生的停顿时间。
可触及性:
一个相对是否可以被当做垃圾回收,需要考察这个对象的可触及性,即在任何情况下,从根节点开始是否可以访问到这个对象。
如果在任何情况下,从所有根节点开始,都无法直接或间接访问到这个对象,则说明这个对象已经不再被使用了,该对象可以被回收。
可触及性设计三种状态:
1、可触及,从根节点开始,可以到达该对象,则称该对象可触及;
2、可复活,对象的所有引用都已释放,但是该对象可以通过调用其finalize方法被复活;
3、不可触及,finalize方法已被调用(finalize只可能被虚拟机调用一次),但没有被复活,该对象就进入不可触及状态。
finalize方法:
finalize方法是一个非常糟糕的反模式,不推荐使用它来释放资源。
首先,finalize方法很可能在无意中复活对象。
其次,finalize方法是由系统调用的,调用时机不明确。
引用强度:
Java中提供了4个级别的引用:
1、强引用;
2、软引用;
3、弱引用;
4、虚引用。
强引用:
强引用就是一般的引用,它不会被垃圾回收器回收。
软引用(java.lang.ref.SoftReference):
软引用比强引用稍微弱一点。
如果某对象只持有软引用,那么当堆空间不足时,就会被回收,因此软引用对象不会引起内存溢出。
弱引用(java.lang.ref.WeakReference):
弱引用比软引用还要弱。
在垃圾回收时,不管系统内存的使用情况如何,只要发现弱引用,就会立即对其进行回收。
弱引用之所以可以在内存中存在,是因为垃圾回收线程的优先级很低,不能立即发现它。
虚引用(java.lang.ref.PhantomReference):
虚引用是所有引用类型中最弱的一个。虚引用和没有引用几乎是一样的,随时都可能被回收。
试图通过虚引用的get方法取得强引用时,总会失败。
虚引用只是为了跟踪垃圾回收过程。
垃圾回收器:
1、串行回收器;
2、并行回收器;
3、CMS回收器;
4、G1回收器。
串行回收器:
每次垃圾回收时,串行回收器都只有一个工作线程。
对于并行能力差的机器,使用串行回收器反而性能更高、效率更好。因为机器并行能力差,启动多个线程并行回收,反而多了线程切换的开销。
串行回收器是独占式的,垃圾回收过程中,所有其他线程都要停止工作。
串行回收器既可以用于新生代,也可以用于老年代。
新生代串行回收器:
新生代串行回收器使用复制算法,容易实现、逻辑处理高效,且没有线程切换的开销。
虚拟机以Client模式启动时,串行回收器是默认回收器。
老年代串行回收器:
老年代串行回收器使用标记压缩算法。
可以使用以下三种参数指明老年代使用串行回收器:
1、-XX:+UseSerialGC参数,新生代、老年代都使用串行回收器;
2、-XX:+UseParNewGC参数(JDK9和JDK10中,该参数已作废),新生代使用ParNew回收器,老年代使用串行回收器;
3、-XX:+UseParallelGC参数,指定新生代使用ParallelGC回收器,老年代使用串行回收器。
并行回收器:
并行回收器使用多个线程同时进行垃圾回收,对于并行能力更强的机型来说,可以有效减少每次垃圾回收所需的时间。
新生代并行回收器(ParNew):
ParNew回收器是新生代垃圾回收器,使用复制算法,它只是简单地将新生代串行回收器多线程化。
ParNew回收器也是独占式的,当它启动时,其他所有线程都要暂停。
-XX:+UseConcMarkSweepGC(JDK9、JDK10中已不建议再使用该参数),新生代使用ParNew回收器,老年代使用CMS回收器。
ParNew回收器的线程数可以通过-XX:ParallelGCThreads参数指定。
该回收器的线程数一般需要与计算机的CPU核数关联,一般情况下:
1、当CPU核数小于8时,ParallelGCThreads的值取CPU的核数;
2、当CPU核数大于8时,ParallelGCThreads的值等于3+(5*CPU_count/8)。
新生代并行回收器(ParallelGC):
ParallelGC回收器也使用复制算法。
看上去ParallelGC回收器和ParNew回收器很相似。不同的是,ParallelGC回收器非常关注系统的吞吐量。
新生代ParallelGC回收器可以使用两种参数启用:
1、-XX:+UseParallelGC,新生代使用ParallelGC回收器,老年代使用串行回收器。
2、-XX:+UseParallelOldGC,新生代使用ParallelGC回收器,老年代使用ParallelOldGC回收器。
ParallelGC回收器提供了两个参数用于控制系统吞吐量:
1、-XX:MaxGCPauseMillis,设置最大停顿时间,该参数值是一个大于0的整数。
指定该参数后,回收器会自动调整Java堆的大小或其他系统参数,尽量把停顿时间控制在MaxGCPauseMillis以内。
MaxGCPauseMillis不能设置得过小,因为过小的话,回收器会把堆调整得很小,这样会造成垃圾回收频繁,系统吞吐量反而更低了。
2、-XX:GCTimeRatio,设置吞吐量大小,该参数值是一个0到100以内的整数。
系统将花费不超过1/(1+GCTimeRatio)的时间进行垃圾回收。
默认GCTimeRatio到取值为99,即有不超过1/(1+99)=1%的时间用于垃圾回收。
-XX:MaxGCPauseMillis参数和-XX:GCTimeRatio参数是互相矛盾的,因为:
如果减小每次垃圾回收的时间,吞吐量也会降低;
而增加吞吐量,又会延长每次垃圾回收的时间。
ParallelGC回收器还可以通过-XX:+UseAdaptiveSizePolicy参数打开自适应GC策略,让虚拟机自行完成GC调优工作。
老年代并行回收器(ParallelOldGC):
ParallelOldGC回收器使用标记压缩算法。
ParallelOldGC回收器也是多线程的,和新生代ParallelGC回收器一样,它也关注吞吐量。
CMS回收器(Concurrent Mark Sweep、并发标记清除):
CMS回收器使用标记清除算法。
CMS回收器主要关注系统停顿时间。
CMS回收器的工作过程:
CMS回收器工作时的主要步骤有:
1、初始标记(独占式);
2、并发标记;
3、预清理;
4、重新标记(独占式);
5、并发清除;
6、并发重置。
启用CMS回收器:
使用参数-XX:+UseConcMarkSweepGC可以声明启用CMS回收器。
并行和并发的区别:
并发是指回收器和应用线程交替执行;
并行是指应用程序完全挂起,同时由多个线程一起执行GC。
CMS回收器的执行:
CMS回收器不是独占式的,在CMS回收过程中,应用线程任然可以继续执行。
应用线程执行过程中,又会产生垃圾对象,这些新的垃圾对象在当前的CMS回收过程中是无法清理的。
所以在CMS回收过程中,要确保应用线程有足够的内存可用。
因此,CMS回收器不会等到内存耗尽的时候才进行垃圾回收,而是在内存使用率到达一定程度时就开始垃圾回收了。
可以通过参数-XX:CMSInitiatingOccupancyFraction指定一个阈值,默认68,即内存使用率到达68%时,CMS回收器就会执行。
CMS阈值的设置原则:
如果内存使用率飞速增长,在CMS回收过程中,已经出现了内存不足的状况,CMS回收就会失败。
CMS失败后,虚拟机会启动老年代串行回收器进行垃圾回收,这时,应用线程会被全部挂起!造成很长的停顿时间。
如果内存使用率上升缓慢,可以将CMSInitiatingOccupancyFraction设大点,以有效降低CMS的触发频率,减少老年代回收次数。
如果内存使用率上升飞快,可以将CMSInitiatingOccupancyFraction设小点,以避免老年代串行回收器的触发频率。
CMS内存压缩参数:
CMS回收器使用的是标记清除算法,这种算法容易产生内存碎片。
为了减少碎片,CMS回收器提供了两个用于压缩内存的参数:
1、-XX:+UseCMSCompactAtFullCollection,CMS垃圾收集完成后,进行一次碎片整理(非并发)。
2、-XX:CMSFullGCBeforeCompaction,设定进行了多少次CMS回收后,进行一次内存压缩。
G1回收器(Garbage First):
G1回收器是JDK1.7中引入的,可以替代CMS回收器。
G1仍旧属于分代回收器。
从堆的结构上看,G1回收器采用了分区算法,新生代和老年代都不必连续。
G1兼顾新生代和老年代,其它回收器要么只工作在新生代,要么只工作在老年代。
G1每次回收都会进行有效的内存复制,减少内存碎片。
由于分区,G1可以每次只回收部分区块,缩小了回收范围,可以有效控制GC停顿。
G1相关参数:
-XX:+UseG1GC,该参数用于声明使用G1回收器。
-XX:MaxGCPauseMillis,该参数用于指定最大停顿时间。
在实际运行过程中,如果任何一次停顿超过MaxGCPauseMillis,G1就会调整新生代和老年代的比例、调整堆大小、调整晋升年龄等,以符合预设目标。
-XX:InitiatingHeapOccupancyPercent,这个参数用于指定当整个堆使用率达到多少时,触发并发标记周期。
InitiatingHeapOccupancyPercent默认值是45,即当整个堆的使用率达到45%时,触发并发标记周期。
InitiatingHeapOccupancyPercent一旦被设置,G1就不会再修改它了。
禁用System.gc():
默认情况下,System.gc()会显式触发Full GC,同时对老年代和新生代进行回收。
使用-XX:-+DisableExplicitGC,可以禁用显式GC,它使System.gc()等价于一个空函数调用。
调用System.gc()时,使用并发回收:
默认情况下,如果没有禁用System.gc(),会使用传统的Full GC方式回收整个堆。
使用参数-XX:+ExplicitGCInvokesConcurrent,可以使用并发方式进行回收。
不使用这个参数,即使启用了CMS或G1,也不会进行并发回收。
TLAB(线程本地分配缓存,Thread Local Allocation Buffer):
TLAB是线程专属的内存分配区域。
在同一时刻,通常会有大量的线程在对上申请内存空间,所以每一次内存分配都必须进行加锁同步,加锁是效率低下的。
TLAB由于是线程专属的,其他线程无法访问,所以能够不用加锁就进行内存分配。
TLAB在eden区。
Java虚拟机(JVM)学习笔记(不定时更新)相关推荐
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- Java虚拟机JVM学习05 类加载器的父委托机制
Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...
- java虚拟机类加载机制_《深入理解java虚拟机》学习笔记一/类加载机制
为何要读这本书? 近期看了左萧龙大哥的单例设计模式,后文讲解到了JVM对类实例化相关知识,感觉看着很无力,不懂,于是乎买本书研究下. 如何读? 个人水平一般,理解程度有限,书中说到每章关联不是很大,所 ...
- Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)
Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...
- java帧结构_Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)...
Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...
- 《深入理解java虚拟机》学习笔记之虚拟机即时编译详解
郑重声明:本片博客是学习<深入理解java虚拟机>一书所记录的笔记,内容基本为书中知识. Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块 ...
- java之jvm学习笔记十三(jvm基本结构)
欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完 ...
- 《深入理解java虚拟机》学习笔记--第三章:垃圾收集器与内存分配策略
GC所关心的问题就是: (1)那些内存需要回收? (2)何时回收? (3)怎么回收? 关注点:在程序计数器.java虚拟机栈.本地方法栈中,这些内存都是随着线程的创建而创建,销毁而销毁,这部分是不需要 ...
- 《深入理解java虚拟机》学习笔记四/垃圾收集器GC学习/一
Grabage Collection GC GC要完毕的三件事情: 哪些内存须要回收? 什么时候回收? 怎样回收? 内存运行时区域的各个部分中: 程序计数器.虚拟机栈.本地方法栈这3个区域随 ...
- 《深入理解JAVA虚拟机》——学习笔记
JVM内存模型以及分区 JVM内存分为: 1.方法区:线程共享的区域,存储已经被虚拟机加载的类信息.常量.静态变量.即时编译器编译后的代码等数据 2.堆:线程共享的区域,存储对象实例,以及给数组分配的 ...
最新文章
- ROS中base_link, odom, fixed_frame, target_frame和虚拟大地图map的关系
- Hystrix 超时配置重写
- 丰富多彩的Android onTouch事件
- 前端项目课程7 banner设计注意事项
- 1024X768大图 (Wallpaper)
- libsvm使用方法总结
- IDEA Maven的下载和配置
- no target device found怎么解决_Linux 使用Unzip提示write error (disk full?)的解决方法
- linux查看python环境_运维笔记linux环境提示python: command not found hello
- 集合类 collection接口 LinkedList
- 利用哈希表设计快速电话号码查询系统
- MMA8452Q 三轴加速度传感器驱动
- ApplePay开发
- 计算机网络科研项目申请书,唐乾利:如何进一步完善医药类科研课题申请书
- Lesson 8 question 1 Dominator
- ESP32开发--使用NVS存储数据
- 华为ebgp_华为设备BGP详细配置
- mysql 写备注_mysql怎么添加备注
- React - review 2
- android 下载apk安装后自动启动,下载apk并启动安装