JVM-垃圾回收与内存分配
目录
垃圾收集器与内存分配策略
引用
对象的访问方式有哪些?(句柄和直接指针)
Java的引用有哪些类型?
如何判断对象是否是垃圾?
请列举一些可作为GC Roots的对象?
对象头了解吗? mark word(hashcode、分代、锁标志位)、指向类信息的指针和数组长度(数组才有)
Object a = new object()的大小
对象引用占多少大小?(类型指针)
执行main方法的过程
创建对象的过程
对象的生命周期
什么是指针碰撞?什么是空闲列表?(用于给对象分配内存)
JVM 里 new 对象时,堆会发生抢占吗?JVM 是怎么设计来保证线程安全的?
垃圾收集器 (主要作用于方法区(常量)和堆(实例对象))
Full GC 的触发条件?
聊聊Java中的GC,分别作用在什么范围
有哪些GC算法? (可达性分析)标记清除算法(内存碎片)->复制算法(内存利用低)->标记整理算法->分代回收
说一下新生代的区域划分?
你知道哪些垃圾收集器?
Serial收集器 (复制 新生代 单线程)
Serial Old 收集器 (单线程 标记整理)
ParNew收集器 (复制 新生代 多线程 )
Parallel Scavenge 收集器 (新生代、多线程 、复制、 关注垃圾回收吞吐量)
Parallel Old 收集器 (多线程 标记整理)
CMS收集器 (并发标记清除,追求最短STW) 老年代
G1收集器(高吞吐低停顿的平衡) 分代回收, 标记整理+复制
ZGC 收集器
工作中项目使用的什么垃圾回收算法?
G1回收器的特色是什么?
GC只会对「堆」进行GC吗? (还会针对方法区)
有了 CMS,为什么还要引入 G1?
垃圾收集器应该如何选择?
垃圾收集器与内存分配策略
引用
对象的访问方式有哪些?(句柄和直接指针)
Java程序会通过栈上的引用操作堆上的具体对象,对象的访问方式由虚拟机决定,主流访问方式主要有句柄和直接指针。
句柄 : 堆会划分出一块内存作为句柄池,引用中存储对象的句柄地址,句柄包含对象实例数据与类型数据的地址信息。
优点是引用中存储的是稳定句柄地址,在GC过程中对象被移动时只会改变句柄的实例数据指针,而引用本身不需要修改。
直接指针 :引用中存储的直接就是对象的地址。对象包含到对象类型数据的指针,通过这个指针可以访问对象类型数据。
使用直接指针访问方式最大的好处就是访问对象速度快,它节省了一次指针定位的时间开销
虚拟机hotspot主要是使用直接指针来访问对象。
Java的引用有哪些类型?
JDK1.2后对引用进行了扩充,按强度分为四种:
强引用:最常见的引用,例如Object obj - new Object()就属于强引用。只要对象有强引用指向且GC Roots可达,在内存回收时即使濒临内存耗尽也不会被回收。
软引用:弱于强引用,描述非必需对象。在系统将发生内存溢出前,会把软引用关联的对象加入回收范围以获得更多内存空间。用来缓存服务器中间计算结果及不需要实时保存的用户行为等。
弱引用:弱于软引用,描述非必需对象。弱引用关联的对象只能生存到下次YGC(Minor GC)前,当垃圾收集器开始工作时无论当前内存是否足够都会回收只被弱引用关联的对象。由于YGC具有不确定性,因此弱引用何时被回收也不确定。
虚引用:最弱的引用,定义完成后无法通过该引用获取对象。唯一目的就是为了能在对象被回收时收到一个系统通知。虚引用必须与引用队列联合使用,垃圾回收时如果出现虚引用,就会在回收对象前把这个虚引用加入引用队列。
虚引用看起来和弱引用没啥区别,只是必须搭配ReferenceQueue。用虚引用的目的一般是跟踪对象被回收的活动。
如何判断对象是否是垃圾?
引用计数:在对象中添加一个引用计数器,如果被引用,计数器加1,引用失效计数器减1,如果计数器为0则被标记为垃圾。原理简单,效率高,但是在Java 中很少使用,因为存在对象间循环引用的问题,导致计数器无法清零。
可达性分析: 主流语言的内存管理都使用可达性分析判断对象是否存活。基本思路是通过称为 GC Roots 的根对象作为起始节点,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到 GC Roots 没有任何引用链相连,则会被标记为垃圾。
可作为 GC Roots的对象包括虚拟机栈和本地方法栈中引用的对象、类静态属性引用的对象、常量引用的对象。 (引用的对象)
请列举一些可作为GC Roots的对象?
所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。
在 Java 中,GC Roots 包括以下几种:
- 在虚拟机栈中引用的对象,例如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
- 在方法区中类静态属性引用的对象,例如Java类的引用类型静态变量。
- 在方法区中常量引用的对象,例如字符串常量池(String Table)里的引用。
- 在本地方法栈中Native方法引用的对象。
- Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
- 所有被同步锁(synchronized关键字)持有的对象。
- 反映Java虚拟机内部情况的JM XBean、JVM TI中注册的回调、本地代码缓存等。
对象头了解吗? mark word(hashcode、分代、锁标志位)、指向类信息的指针和数组长度(数组才有)
在 HotSpot 中,对象在堆内存中的存储布局可以划分为三个部分:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。
- 对象的实例数据就是存储了对象的具体信息,属性和类型。
- 对齐填充字节:因为JVM要求对象占的内存大小是8bit 的倍数,因此后面有几个字节用于把对象的大小补齐至 8bit的倍数。(空间换时间)
CPU 进行内存访问时,一次寻址的指针大小是 8 字节,正好是 L1 缓存行的大小。如果不进行内存对齐,则可能出现跨缓存行访问,导致额外的缓存行加载,降低了 CPU 的访问效率。
- 对象头由以下三部分组成:mark word、指向类信息的指针和数组长度(数组才有)。
- mark word 包含:包含了对象自身的运行时数据,如哈希码(HashCode)、垃圾回收分代年龄、锁状态标志、线程持有的锁、偏向线程 ID 等信息。在 64 位操作系统下占 8 个字节,32 位操作系统下占 4 个字节。
- 类型指针(Class Pointer):指向对象所属类的元数据的指针,JVM 通过这个指针来确定对象的类。在开启了压缩指针的情况下,这个指针可以被压缩。在开启指针压缩的情况下占 4 个字节,否则占 8 个字节。在 JDK 8 中,压缩指针默认是开启的,以减少 64 位应用中对象引用的内存占用。
内存对齐的主要作用是:
- 平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。
Object a = new object()的大小
一般来说,对象的大小是由对象头、实例数据和对齐填充三个部分组成的。
- 对象头的大小在 32 位 JVM 上是 8 字节,在 64 位 JVM 上是 16 字节(如果开启了压缩指针,就是 12 字节)。
- 实例数据的大小取决于对象的属性和它们的类型。对于
new Object()
来说,Object 类本身没有实例字段,因此这部分可能非常小或者为零。 - 对齐填充的大小取决于对象头和实例数据的大小,以确保对象的总大小是 8 字节的倍数。
一般来说,目前的操作系统都是 64 位的,并且 JDK 8 中的压缩指针是默认开启的,因此在 64 位 JVM 上,new Object()
的大小是 16 字节(12 字节的对象头 (8+4)+ 4 字节的对齐填充)。
对象引用占多少大小?(类型指针)
在 64 位 JVM 上,未开启压缩指针时,对象引用占用 8 字节;开启压缩指针时,对象引用可被压缩到 4 字节。
而 HotSpot JVM 默认开启了压缩指针,因此在 64 位 JVM 上,对象引用占用 4 字节。
执行main方法的过程
- 编译.java后得到.class 后,执行这个class文件,系统会启动一个JVM进程,进行类的加载,根据全限定名找到二进制字节文件,转化成方法区的运行时数据结构。
- JVM 找到的主程序入口,执行main方法。
- main方法的第一条语句为Person p = new Person("大彬"),就是让JVM创建一个Person 对象,但是这个时候方法区中是没有Person类的信息的,所以JVM马上加载 Person类,把Person类的信息放到方法区中。
- 加载完Person类后,JVM 在堆中分配内存给Person 对象,然后调用构造函数初始化 Person 对象,这个Person 对象持有指向方法区中的Person类的类型信息的引用。
- 执行p.getName()时,JVM根据 p 的引用找到 p 所指向的对象,然后根据此对象持有的引用定位到方法区中Person类的类型信息的方法表,获得getName()的字节码地址。
- 执行getName()方法。
创建对象的过程
在Java中创建对象的过程包括以下几个步骤:
- 类加载检查:虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
- 分配内存:在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。
- 初始化零值:内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(成员变量,数值类型是 0,布尔类型是 false,对象类型是 null)
-
- (不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
- 进行必要设置,比如对象头:初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、对象的哈希码、对象的 GC 分代年龄等信息。这些信息存放在对象头中。另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
- 执行 init 方法:在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始——构造函数,即class文件中的方法还没有执行,所有的字段都还为零,对象需要的其他资源和状态信息还没有按照预定的意图构造好。所以一般来说,执行 new 指令之后会接着执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全被构造出来。将成员变量赋值为预期的值
对象的生命周期
对象的生命周期包括创建、使用和销毁三个阶段:
- 创建:对象通过关键字new在堆内存中被实例化,构造函数被调用,对象的内存空间被分配。
- 使用:对象被引用并执行相应的操作,可以通过引用访问对象的属性和方法,在程序运行过程中被不断使用。
- 销毁:当对象不再被引用时,通过垃圾回收机制自动回收对象所占用的内存空间。垃圾回收器会在适当的时候检测并回收不再被引用的对象,释放对象占用的内存空间,完成对象的销毁过程。
什么是指针碰撞?什么是空闲列表?(用于给对象分配内存)
在堆内存分配对象时,主要使用两种策略:指针碰撞和空闲列表。
①、指针碰撞(Bump the Pointer)
假设堆内存是一个连续的空间,分为两个部分,一部分是已经被使用的内存,另一部分是未被使用的内存。
在分配内存时,Java 虚拟机维护一个指针,指向下一个可用的内存地址,每次分配内存时,只需要将指针向后移动(碰撞)一段距离,然后将这段内存分配给对象实例即可。
②、空闲列表(Free List)
JVM 维护一个列表,记录堆中所有未占用的内存块,每个空间块都记录了大小和地址信息。
当有新的对象请求内存时,JVM 会遍历空闲列表,寻找足够大的空间来存放新对象。
分配后,如果选中的空闲块未被完全利用,剩余的部分会作为一个新的空闲块加入到空闲列表中。
指针碰撞适用于管理简单、碎片化较少的内存区域(如年轻代),而空闲列表适用于内存碎片化较严重或对象大小差异较大的场景(如老年代)。
JVM 里 new 对象时,堆会发生抢占吗?JVM 是怎么设计来保证线程安全的?
会,假设 JVM 虚拟机上,每一次 new 对象时,指针就会向右移动一个对象 size 的距离,一个线程正在给 A 对象分配内存,指针还没有来的及修改,另一个为 B 对象分配内存的线程,又引用了这个指针来分配内存,这就发生了抢占。
有两种可选方案来解决这个问题:
- 采用CAS 分配重试的方式来保证更新操作的原子性
- 每个线程在 Java 堆中预先分配一小块内存,也就是本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),要分配内存的线程,先在本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定。
垃圾收集器 (主要作用于方法区(常量)和堆(实例对象))
Full GC 的触发条件?
对于Minor GC,其触发条件比较简单,当Eden 空间满时,就将触发一次Minor GC。
而Full GC触发条件相对复杂,有以下情况会发生 full GC:
- 调用 System.gc()
只是建议虚拟机执行 Full GC,但是虚拟机不一定真正去执行。不建议使用这种方式,而是让虚拟机管理内存。
- 老年代空间不足
老年代空间不足的常见场景为大对象直接进入老年代、长期存活的对象进入老年代等。为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。
除此之外,可以通过 -Xmn参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代。还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄,让对象在新生代多存活一段时间。
- 空间分配担保失败
新生代的 To 区放不下从 Eden 和 From 拷贝过来对象,或者新生代对象 GC 年龄到达阈值需要晋升这两种情况,老年代如果放不下的话都会触发 Full GC。
- JDK 1.7及以前的永久代空间不足
在JDK 1.7及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放的为一些Class的信息、常量、静态变量等数据。当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用CMS GC 的情况下也会执行 Full GC。如果经过 Full GC仍然回收不了,那么虚拟机抛出 java.lang.OutOfMemoryError。
聊聊Java中的GC,分别作用在什么范围
- 新生代收集(Minor GC / Young GC) 只是新生代的垃圾收集
- 老年代收集 (Major GC / Old GC) 只是老年代的垃圾收集(目前只有CMS GC会有单独收集老年代的行为)
- 整堆收集(Full GC)收集整个堆和方法区(元空间)的垃圾
- 混合收集(Mixed GC)收集整个新生代以及部分老年代的垃圾收集 (目前只有G1会有这种行为)
有哪些GC算法? (可达性分析)标记清除算法(内存碎片)->复制算法(内存利用低)->标记整理算法->分代回收
Java的内存回收机制基于自动内存管理,开发人员无需手动释放内存。垃圾回收器会自动识别不再使用的对象,并回收它们所占用的内存空间。
垃圾回收算法主要有 :
- 标记-清除算法:标记-清除算法分为“标记”和“清除”两个阶段,首先通过可达性分析,标记出所有需要回收的对象,然后统一回收所有被标记的对象。
-
- 标记-清除算法有两个缺陷,一个是效率问题,标记和清除的过程效率都不高,另外一个就是,清除结束后会造成大量的碎片空间。有可能会造成在申请大块内存的时候因为没有足够的连续空间导致再次 GC。
- 复制算法:为了解决碎片空间的问题,出现了“复制算法”。复制算法的原理是,将内存分成两块,每次申请内存时都使用其中的一块,当内存不够时,将这一块内存中所有存活的复制到另一块上。然后将然后再把已使用的内存整个清理掉。
-
- 复制算法解决了空间碎片的问题。但是也带来了新的问题。因为每次在申请内存时,都只能使用一半的内存空间。内存利用率严重不足。
- 标记-整理算法:复制算法在 GC 之后存活对象较少的情况下效率比较高,但如果存活对象比较多时,会执行较多的复制操作,效率就会下降。而老年代的对象在 GC 之后的存活率就比较高,所以就有人提出了“标记-整理算法”。标记-整理算法的“标记”过程与“标记-清除算法”的标记过程一致,但标记之后不会直接清理。而是将所有存活对象都移动到内存的一端。移动结束后直接清理掉剩余部分。
- 分代回收算法:分代收集是将内存划分成了新生代和老年代。分配的依据是对象的生存周期,或者说经历过的 GC 次数。对象创建时,一般在新生代申请内存,当经历一次 GC 之后如果对还存活,那么对象的年龄 +1。当年龄超过一定值(默认是 15,可以通过参数 -XX:MaxTenuringThreshold 来设定)后,如果对象还存活,那么该对象会进入老年代。
说一下新生代的区域划分?
新生代的垃圾收集主要采用标记-复制算法,因为新生代的存活对象比较少,每次复制少量的存活对象效率比较高。
基于这种算法,虚拟机将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次分配内存只使用 Eden 和其中一块 Survivor。发生垃圾收集时,将 Eden 和 Survivor 中仍然存活的对象一次性复制到另外一块 Survivor 空间上,然后直接清理掉 Eden 和已用过的那块 Survivor 空间。默认 Eden 和 Survivor 的大小比例是 8∶1。
你知道哪些垃圾收集器?
垃圾回收器主要分为以下几种:Serial、ParNew、Parallel Scavenge、Serial old、 Parallel old、CMS、G1.
Serial收集器 (复制 新生代 单线程)
单线程收集器,使用一个垃圾收集线程去进行垃圾回收,在进行垃圾回收的时候必须暂停其他所有的工作线程(Stop The World),直到它收集结束。
特点:简单高效;内存消耗小;没有线程交互的开销,单线程收集效率高;需暂停所有的工作线程,用户体验不好。
Serial 是虚拟机在客户端模式的默认新生代收集器
Serial Old 收集器 (单线程 标记整理)
Serial收集器的老年代版本,单线程收集器,使用标记整理算法。
ParNew收集器 (复制 新生代 多线程 )
Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其他行为、参数与 Serial 收集器基本一致。
Parallel Scavenge 收集器 (新生代、多线程 、复制、 关注垃圾回收吞吐量)
新生代收集器,基于复制算法实现的收集器。特点是吞吐量优先,能够并行收集的多线程收集器,允许多个垃圾回收线程同时运行,降低垃圾收集时间,提高吞吐量。
Parallel Scavenge收集器关注点是吞吐量,高效率的利用 CPU资源。
Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的
-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。
- -XX:MaxGCPauseMillis参数的值是一个大于0的毫秒数,收集器将尽量保证内存回收花费的时间不超过用户设定值。
- -XX:GCTimeRatio参数的值大于0小于100,即垃圾收集时间占总时间的比率,相当于吞吐量的倒数。
Parallel Old 收集器 (多线程 标记整理)
Parallel Scavenge收集器的老年代版本。多线程垃圾收集,使用标记整理算法。
CMS收集器 (并发标记清除,追求最短STW) 老年代
初始标记和重新标记会 STW,JDK 1.5 时引入,JDK9 被标记弃用,JDK14 被移除。
Concurrent Mark Sweep,并发标记清除,追求获取最短停顿时间,实现了让垃圾收集线程与用户线程基本上同时工作。
CMS垃圾收集器关注点更多的是用户线程的停顿时间。
CMS垃圾回收基于标记清除算法实现,整个过程分为四个步骤:
- 初始标记:暂停所有用户线程(Stop The World),记录直接与GCRoots直接相连的对象。
- 并发标记:从GC Roots 开始对堆中对象进行可达性分析,找出存活对象,耗时较长,但是不需要停顿用户线程。
- 重新标记:在并发标记期间对象的引用关系可能会变化,需要重新进行标记。此阶段也会暂停所有用户线程。
- 并发清除:清除标记对象,这个阶段也是可以与用户线程同时并发的。
在整个过程中,耗时最长的是并发标记和并发清除阶段,这两个阶段垃圾收集线程都可以与用户线程一起工作,所以从总体上来说,CMS收集器的内存回收过程是与用户线程一起并发执行的。
优点:并发收集,停顿时间短。
缺点:
- 标记清除算法导致收集结束有大量空间碎片。
- 产生浮动垃圾,在并发清理阶段用户线程还在运行,会不断有新的垃圾产生,这一部分垃圾出现在标记过程之后,CMS 无法在当次收集中回收它们,只好等到下一次垃圾回收再处理;
G1收集器(高吞吐低停顿的平衡) 分代回收, 标记整理+复制
G1(Garbage-First Garbage Collector)在 JDK 1.7 时引入,在 JDK 9 时取代 CMS 成为了默认的垃圾收集器。G1 有五个属性:分代、增量、并行、标记整理、STW。
G1垃圾收集器的目标是在不同应用场景中追求高吞吐量和低停顿之间的最佳平衡。
G1将整个堆分成相同大小的分区 ( Region),有四种不同类型的分区:Eden、 Survivor、Old和Humongous。分区的大小取值范围为1M到 32M,都是2的幂次方。
分区大小可以通过 -XX:G1HeapRegionSize 参数指定。
Humongous区域用于存储大对象。G1规定只要大小超过了一个分区容量一半的对象就认为是大对象。
G1收集器对各个分区回收所获得的空间大小和回收所需时间的经验值进行排序,得到一个优先级列表,每次根据用户设置的最大回收停顿时间,优先回收价值最大的分区。也是名字的由来(Garbage-First)
特点:可以由用户指定期望的垃圾收集停顿时间。
G1收集器的回收过程分为以下几个步骤:
- 初始标记。暂停所有其他线程,记录直接与GC Roots直接相连的对象,耗时较短。
- 并发标记。从GC Roots 开始对堆中对象进行可达性分析,找出要回收的对象,耗时较长,不过可以和用户程序并发执行。
- 最终标记。需对其他线程做短暂的暂停,用于处理并发标记阶段对象引用出现变动的区域。
- 筛选回收。对各个分区的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,然后把决定回收的分区的存活对象复制到空的分区中,再清理掉整个旧的分区的全部空间。
G1 在垃圾回收期间仍然需要「Stop the World」。不过,G1 在停顿时间上添加了预测机制,用户可以 JVM 启动时指定期望停顿时间,G1 会尽可能地在这个时间内完成垃圾回收。
这里的操作涉及存活对象的移动,会暂停用户线程,由多条收集器线程并行完成。
ZGC 收集器
ZGC 是 JDK 11 时引入的一款低延迟的垃圾收集器,它的目标是在不超过 10ms 的停顿时间内,为堆大小达到 16TB 的应用提供一种高吞吐量的垃圾收集器。
ZGC 的两个关键技术:指针染色和读屏障,不仅应用在并发转移阶段,还应用在并发标记阶段:将对象设置为已标记,传统的垃圾回收器需要进行一次内存访问,并将对象存活信息放在对象头中;而在 ZGC 中,只需要设置指针地址的第 42-45 位即可,并且因为是寄存器访问,所以速度比访问内存更快。
工作中项目使用的什么垃圾回收算法?
我们生产环境中采用了设计比较优秀的 G1 垃圾收集器,G1 采用的是分区式标记-整理算法,将堆划分为多个区域,按需回收,适用于大内存和多核环境,能够同时考虑吞吐量和暂停时间。
或者:
我们系统采用的是 CMS 收集器,CMS 采用的是标记-清除算法,能够并发标记和清除垃圾,减少暂停时间,适用于对延迟敏感的应用。
再或者:
我们系统采用的是 Parallel 收集器,Parallel 采用的是年轻代使用复制算法,老年代使用标记-整理算法,适用于高吞吐量要求的应用。
G1回收器的特色是什么?
G1回收器的特色在于它将堆内存划分成多个大小相等的独立区域,并且通过维护一个优先列表来进行局部区域的垃圾收集,从而减少全堆垃圾收集的频率和停顿时间。G1也特别注重停顿时间的可预测性,并允许用户指定期望的停顿时间目标。
GC只会对「堆」进行GC吗? (还会针对方法区)
主要的垃圾收集活动确实发生在堆内存中,因为这是大多数Java对象存活和死亡的地方。不过,方法区也是垃圾收集的目标之一,例如回收废弃常量和无用的类。
程序计数器、虚拟机栈和本地方法栈通常随线程而生,随线程而灭,所以它们不是垃圾收集的目标。
有了 CMS,为什么还要引入 G1?
CMS 适用于对延迟敏感的应用场景,主要目标是减少停顿时间,但容易产生内存碎片。G1 则提供了更好的停顿时间预测和内存压缩能力,适用于大内存和多核处理器环境。
垃圾收集器应该如何选择?
这里简单地列一下上面提到的一些收集器的适用场景:
- Serial :如果应用程序有一个很小的内存空间(大约 100 MB)亦或它在没有停顿时间要求的单线程处理器上运行。
- Parallel:如果优先考虑应用程序的峰值性能,并且没有时间要求要求,或者可以接受 1 秒或更长的停顿时间。
- CMS/G1:如果响应时间比吞吐量优先级高,或者垃圾收集暂停必须保持在大约 1 秒以内。
- ZGC:如果响应时间是高优先级的,或者堆空间比较大。
自己整理,借鉴很多博主,感谢他们
相关文章:
JVM-垃圾回收与内存分配
目录 垃圾收集器与内存分配策略 引用 对象的访问方式有哪些?(句柄和直接指针) Java的引用有哪些类型? 如何判断对象是否是垃圾? 请列举一些可作为GC Roots的对象? 对象头了解吗? mark word(hashcode、分代、锁标志位)、…...
Jolt路线图
1. 引言 a16z crypto团队2024年7月更新了其Jolt路线图: 主要分为3大维度: 1)链上验证维度: 1.1)Zeromorph:见Aztec Labs团队2023年论文 Zeromorph: Zero-Knowledge Multilinear-Evaluation Proofs from…...
NEEP-EN2-2019-Text4
英二-2019-Text4摘自赫芬顿邮报《The Huffington Post》2018年6月的一篇名为“Let’s Stop Pretending Quitting Straws Will Solve Plastic Pollution”的文章。 以下为个人解析,非官方公开标准资料,可能有误,仅供参考。(单词解释…...
docker 部署wechatbot-webhook 并获取接口实现微信群图片自动保存到chevereto图库等
功能如图: docker部署 version: "3" services:excalidraw:image: dannicool/docker-wechatbot-webhook:latestcontainer_name: wechatbot-webhookdeploy:resources:limits:cpus: 0.15memory: 500Mreservations:cpus: 0.05memory: 80Mrestart: alwayspor…...
OpenWrt安装快速入门指南
在刷新 OpenWrt 固件之前,建议进行以下准备: 1、不要急于安装,慢慢来。如果在安装过程中出现奇怪之处,请先找到答案,然后再继续。 2、准备好设备的精确型号,以便能够选择正确的OpenWrt固件。 3、手上有关…...
AIGC Kolors可图IP-Adapter-Plus风格参考模型使用案例
参考: https://huggingface.co/Kwai-Kolors/Kolors-IP-Adapter-Plus 代码环境安装: git clone https://github.com/Kwai-Kolors/Kolors cd Kolors conda create --name kolors python=3.8 conda activate kolors pip install -r requirements.txt python3 setup.py install…...
从零开始学量化~Ptrade使用教程(七)——期权相关操作
期权交易 可点击证券代码右侧的选,进入期权选择菜单。通过选择标的商品,认购期权和认沽期权中间的选项(包括代码、成交价、幅度%、隐波%、内在价值、时间价值等),以及认购期权或认沽期权,选择所需的期权标的…...
TeamViewer关闭访问密码或固定一组密码不变
TeamViewer的新UI界面变化较大,网上的一些信息已经不再有效,更新后的访问密码在如下图所示: 演示的版本为7.21.4—— 设置每次你的设备访问的密码...
iMazing 3 换手机后苹果游戏数据还有吗 换iPhone怎么转移游戏数据
当你想要更换手机,无论是选择升级到最新款iPhone,或者换到“经典”旧款iPhone,单机游戏数据的转移总是让人发愁。本文将详细介绍换手机后苹果游戏数据还有吗,以及换iPhone怎么转移游戏数据,确保你能无缝继续你的游戏体…...
正则表达式:电子邮件地址的格式详解,及常见正则表达式符号的详细解释和匹配方式
一、第一部分是对该段电子邮件的详解 var Regex /^(?:\w\.?)*\w(?:\w\.)*\w$/; 1.^:这个符号表示匹配输入字符串的开始位置。 2.(?:...):这是一个非捕获组(non-capturing group),用于将正则表达式的一部分组合在…...
AWS全服务历史年表:发布日期、GA和服务概述一览(一)
我一直在尝试从各种角度撰写关于Amazon Web Services(AWS)的信息和魅力。由于我喜欢技术历史,这次我总结了AWS服务发布的历史年表。 虽然AWS官方也通过“Whats New”发布了官方公告,但我一直希望能有一篇文章将公告日期、GA日期&…...
现场可重构CPLD芯片应用案例—蓝牙音箱
我司英尚微提供的高性能数模混合现场可重构IC、通用可配置的模数混合芯片内部集成丰富的模拟资源和数字资源,可轻松替代电路中的各种标准器件,并按照客户要求组合成最优小型ASIC,缩短开发周期,降低成本。下面介绍LS98002现场可重构…...
vue2关于Object.defineProperty实现响应式
实现步骤: 1. 初始化阶段 当 Vue 实例化时,会遍历data 选项中的属性,并使用 Object.defineProperty 将它们转换为 getter 和 setter。这样一来,每当访问或修改这些属性时, Vue就能捕获到这些操作,从而实现…...
中英双语介绍一级市场(Primary Market)和二级市场(Secondary Market)
中文版 一级市场和二级市场是金融市场中的两个主要部分,分别对应证券发行和交易的不同阶段。 一级市场(Primary Market) 定义: 一级市场,又称新发行市场,是指证券首次发行和出售的市场。在一级市场中&am…...
OpenCV 轮廓检测
在 OpenCV 中,轮廓检测是一种用于查找图像中具有相似颜色或强度的连通像素组的技术,这些像素组通常代表了图像中的物体边缘。轮廓可以用来识别和分割图像中的物体,是计算机视觉应用中的一个重要步骤,如目标识别、形状分析等。 轮…...
ubuntu源码安装Odoo
序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo具有非常多的安装方式,除了我最爱用的 apt-get install,我们还可以使用git拉取Odoo源码进行安装。 本次示例于ubuntu20.04 Desktop上进行操作,理论上在ubuntu14.04之后都可以用此操作。 …...
大鲸鱼docker-compose单机容器集群编排工具
目录 一、Docker-compose 概述 二、Docker-compose简介 三、YML文件格式及编写注意事项 1.yml文件是什么 2.yml问价使用注意事项 3.yml文件的基本数据结构 四、Docker-compose 配置 1.Docker-Compose 配置常用字段 2.Docker Compose常用命令 3.使用Docker-compose创建…...
Dify中的高质量索引模式实现过程
思考在什么情况下会使用到高质量索引模式呢?第1种情况是在知识库中上传文档,文档被拆分为段落后需要进行编码(增加);第2种情况是在召回测试的时候,需要对query进行编码(查询);第3种情况是当文档中的段落增加和更新时需要进行编码(增加和更新)。索引模式是针对知识库…...
GO:Socket编程
目录 一、TCP/IP协议族和四层模型概述 1.1 互联网协议族(TCP/IP) 1.2 TCP/IP四层模型 1. 网络访问层(Network Access Layer) 2. 网络层(Internet Layer) 3. 传输层(Transport Layer&#…...
wls2下的centos使用桥接模式连接宿主机网络独立静态ip
前提:wsl2已安装,可正常更新 1.在控制面板中,打开开启或关闭windows功能,将里面的 Hyper-V功能打开,此处涉及重启 2. 按一下win键,输入hy,上面可以看到Hyper-V Manager,点进去 3.选择右边的 Vi…...
R语言实现神经网络ANN
# 常用激活函数 # 自定义Sigmoid函数 sigmod <- function(x){return(1/(1exp(-x))) } # 绘制Sigmoid曲线 x <- seq(-10,10,length.out 100) plot(x,sigmod(x),type l,col blue,lwd 2,xlab NA,ylab NA,main Sigmoid函数曲线)# 自定义Tanh函数 tanh <- function(…...
实战:shell脚本练习
高效编写Bash脚本的技巧 总结了10个实用技巧,帮助提高脚本的效率和可靠性,具体包括: 多写注释:在脚本中添加注释,以帮助理解脚本的不同部分。 当运行失败时使脚本退出:使用set -o errexit或set -e&#x…...
常见排序算法总结
文章目录 比较排序冒泡排序选择排序插入排序归并排序快速排序堆排序希尔排序 非比较排序(桶排序)计数排序基数排序 比较排序 冒泡排序 嵌套循环,每次内层循环执行时,数组的每两个元素交换,将一个最大/小的数排到数组…...
网页HTTP协议 get请求和post请求区别?(HTTP中Get、Post、Put与Delete的区别)(HTTP请求方法、HTTP请求方式、HTTP方法)
文章目录 设计GET、POST、DELETE 等多种请求方法的原因1. 符合语义化设计2. 允许服务器对不同的请求方法进行优化处理3. 提高数据传输的安全性4. 遵循现有的网络架构5. 提高网络通信的效率6. 支持 RESTful API 设计 设计GET、POST、DELETE 等多种请求方法的原因 后端之所以要分…...
攻防世界 re新手模式
Reversing-x64Elf-100 64位ida打开 看if语句,根据i的不同,选择不同的数组,后面的2*i/3选择数组中的某一个元素,我们输入的是a1 直接逆向得到就行 二维字符数组写法:前一个是代表有几个字符串,后一个是每…...
Ajax是什么?如何在HTML5中使用Ajax?
Ajax是什么,它如何工作? Ajax是什么 Ajax,全称Asynchronous Javascript And XML(异步JavaScript和XML),是一种创建交互式网页应用的网页开发技术。它允许网页在不重新加载整个页面的情况下,与…...
Python+Flask+MySQL/Sqlite的个人博客系统(前台+后端管理)【附源码,运行简单】
PythonFlaskMySQL/Sqlite的个人博客系统(前台后端管理)【附源码,运行简单】 总览 1、《个人博客系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 管理员登录2.2 程序主页面2.3 笔记新增界面2.4 文章新增界面2.5 文章/笔记管理界面2…...
【Android性能优化】Android CPU占用率检测原理和优化方向
【Android性能优化】Android CPU占用率检测原理和优化方向 CPU相关知识 CPU占用的基本计算公式 (1 - 空闲态运行时间/总运行时间) * 100% Hz、Tick、Jiffies: Hz:Linux核心每隔固定周期会发出timer interrupt (IRQ 0),HZ是用来定义每一秒有…...
AWS Certified Developer Associate备考笔记
AWS Certified Developer Associate备考笔记 缓慢更新中,如果你也正在关注该考试,请点赞后评论感兴趣的章节,可加快我的更新速度 😃 文章目录 AWS Certified Developer Associate备考笔记一、IAM二、EC2三、EC2 Instance Storage…...
数据质量8个衡量标准
在数据驱动的时代,数据质量对于企业的决策和业务运营至关重要。为了确保数据的有效性和可靠性,我们需要根据一些关键要素来衡量数据的质量。本文将介绍数据质量的8个衡量标准,包括准确性、精确性、真实性、及时性、即时性、完整性、全面性和关…...
wordpress主题安装ftp/江苏seo平台
文章目录1、文件结构速览2、创建appcam2.py;3、创建index.html:4、创建camera.html:5、创建style.css:6、启动服务7、验证上一节我们用flask创建了一个视频流媒体服务器,这一节让我们用Flask创建另一个python 网络服务…...
公众号可以添加wordpress/企业网站推广有哪些
1、前言 在嵌入式系统开发应用平台中,tftp、nfs和samba服务器是最常用的文件传输工具,tftp和nfs是在嵌入式Linux开发环境中经常使用的传输工具,samba则是Linux和Windows之间的文件传输工具。 samba是模仿Windows网上邻居的SMB的通讯协议&am…...
十年前网站开发语言/安卓内核级优化神器
1 静态方法加载几次? 2 类内方法需要加static吗?类外方法呢? 3 class aa{} BOO xx(){} bb.x() cc.row上方代码分别是什么含义? 4 判断返回值类型应看哪里? 5 定义成员变量的方式有几种?可以直接在成员变量下…...
wordpress粒子北京/常用的搜索引擎
1 问题提出 在Windows10VS2015环境中,有些程序需要管理员身份才能正确运行。例如 HANDLE hDevice CreateFile(_T("\\\\.\\PhysicalDrive0"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);if (hDe…...
电子商务网站开发实例/网络营销与策划实践报告
中国银行数据平台2.0改造升级 项目的进度已经接近尾声,回想起项目刚开始的那份期待已经落实,人生中的风景有很多走过一处就要为自己留念,今天就为这个项目留念一下 项目背景 中国银行北京分行的数据是依托中国银行总行的,总行每天…...
网页升级访问未成年/绍兴seo排名外包
摘要: 最近做项目中遇到批量添加和修改的问题,在老大的指导下学会了使用表类型参数来做批量操作。为了巩固强化,围绕这个技术又做了个小demo。 开始正题: 首先,我们在SQL Server 2008下创建一个示例数据库名为Table…...