程序计数器:定位当前线程执行代码在内存中的位置
栈内存(虚拟机栈):生命周期与线程相同,包括局部变量表,动态链接(被调用方法的实际地址),方法出口(方法返回值要返回到的地址)
本地方法栈:为虚拟机使用到的Native方法服务
Java堆:存放对象实例,物理上可以不连续,逻辑上连续即可,包括对象,数组,非静态变量
方法区:包括静态变量,常量,类的元数据等
Java垃圾收集器是Java虚拟机(JVM)的一部分,用于管理内存中不再被程序使用的对象,以释放内存资源。垃圾收集器主要负责以下任务:
Java垃圾收集器的作用范围可以分为两个主要区域:
不同的Java应用可能需要选择不同的垃圾收集器来满足其性能和内存管理的需求。一些应用可能更关注低延迟,而另一些应用可能更关注吞吐量。因此,Java提供了不同的垃圾收集器,以便开发人员可以根据应用的特点进行选择和配置。
需要注意的是,Java的垃圾收集器是一个庞大的主题,不同版本的JVM可能会有不同的垃圾收集器,并且不同的垃圾收集器在性能和行为方面也有差异。因此,在选择和配置垃圾收集器时,需要考虑应用的具体需求和JVM版本的特点。
在Java的垃圾回收中,内存区域通常被划分为多个不同的区域,其中最常见的是新生代(Young Generation)和老年代(Tenured/Old Generation)。它们之间有以下主要区别:
总之,新生代和老年代在Java的内存管理中具有不同的角色和特点。新生代用于存放短生命周期的对象,采用高效的垃圾回收算法,而老年代用于存放长生命周期的对象,通常需要更复杂的垃圾回收策略。这种内存划分有助于提高垃圾回收的效率和降低停顿时间,同时有效地管理内存中的对象。
垃圾回收策略是Java虚拟机(JVM)用来管理内存和自动回收不再被程序引用的对象的一种重要机制。不同的垃圾回收策略适用于不同的应用场景和需求,以下是一些常见的垃圾回收策略:
不同的应用场景和需求会选择不同的垃圾回收策略。在实际应用中,可以根据应用程序的内存特点和性能需求来选择合适的垃圾回收器和策略。
新生代(Young Generation)的垃圾回收通常使用复制(Copying)算法来进行垃圾回收。新生代是堆内存的一部分,主要用于存放新创建的对象。由于新生代的对象生命周期相对较短,因此适合使用复制算法进行垃圾回收。
复制算法的基本思想是将新生代划分为两个相等大小的区域,通常称为Eden区和两个Survivor区(通常称为S0和S1)。当对象被创建时,它们会被分配到Eden区。然后,垃圾回收器会定期检查Eden区中的存活对象,并将它们复制到其中一个Survivor区,同时清空Eden区。垃圾回收器会轮流使用两个Survivor区,每次将存活对象从Eden区复制到一个Survivor区,然后清空Eden区和之前使用的Survivor区。这个过程称为Minor GC(年轻代垃圾回收)。
老年代(Old Generation)垃圾回收的过程通常被称为 “Full GC”(Full Garbage Collection),也称为 “Major GC”。Full GC 是指对整个堆内存进行垃圾回收,包括新生代和老年代。它的主要目的是回收老年代中的存活对象,并进行内存整理,以减少内存碎片。
Full GC 的发生通常是由于以下几种情况之一:
System.gc()
方法来请求进行 Full GC,但这不是推荐的做法。Full GC 通常会导致较长的停顿时间,因为它需要对整个堆内存进行扫描、标记、清除和整理操作。在某些情况下,停顿时间可能会对应用程序的性能和响应时间产生不利影响,因此需要谨慎考虑堆大小和垃圾回收策略,以减小 Full GC 的频率和影响。
为了减少 Full GC 的影响,可以采用以下措施:
总之,Full GC 是老年代垃圾回收的一种重要过程,它会对应用程序的性能产生影响(通常会导致较长的停顿时间,因为它需要对整个堆内存进行操作),因此需要合理配置和管理堆内存以减少 Full GC 的发生。
引用计数算法
给对象添加一个引用计数器,每当一个地方用它时,计数器加1;当引用失效时,计数器减1,当计数器为0时回收。但是无法回收相互循环引用,所以Java没有使用这个方式
根搜索算法(可达性算法)
Java和C#都是采用这种算法。通过一系列的GC Root的对象(有一个GC Root Set)作为起始点,从这些节点开始向下搜索,搜索过的路径称为引用链,当一个对象到GC Root没有任何引用链时,证明可以被回收。
JVM参数有很多种,用于控制Java虚拟机的行为。以下是一些常见的JVM参数,它们用于不同的用途:
-Xmx<size>
:设置Java堆的最大内存使用量,例如 -Xmx512m
表示最大堆内存为512MB。-Xms<size>
:设置Java堆的初始内存使用量,例如 -Xms256m
表示初始堆内存为256MB。-XX:+UseSerialGC
:使用串行垃圾回收器。-XX:+UseParallelGC
:使用并行垃圾回收器。-XX:+UseConcMarkSweepGC
:使用CMS垃圾回收器。-XX:+UseG1GC
:使用G1垃圾回收器。-XX:MaxPermSize=<size>
:设置永久代的最大内存使用量。-XX:MaxMetaspaceSize=<size>
:设置元空间的最大内存使用量。-XX:MaxDirectMemorySize=<size>
:设置直接内存的最大使用量。-server
:启用服务器模式,优化性能。-client
:启用客户端模式,用于开发和调试。-Xdebug
:启用远程调试。-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=<address>
:配置远程调试参数。-D<property>=<value>
:设置系统属性,例如 -Dfile.encoding=UTF-8
。-verbose:gc
:打印垃圾回收日志。-XX:HeapDumpOnOutOfMemoryError
:在内存溢出时生成堆转储文件。这些只是一些常见的JVM参数示例,实际上有许多其他参数可用于微调Java应用程序的性能和行为。你可以根据你的需求和应用程序的性能要求来选择和配置适当的参数。
父类静态代码块 -> 子类静态代码块 ->父类普通代码块 -> 父类构造方法 -> 子类普通代码块 -> 子类构造方法
静态代码块和普通代码块都是类的一部分(类比成员变量),静态代码块是类属性,只会执行一次,普通代码块是对象属性,每构造一个对象,就会被隐式调用一次!
finally语句块在两种情况下不会被执行: