垃圾回收机制

Garbage Collection,GC

垃圾回收是Java的重要功能之一。

|--堆内存:垃圾回收机制只回收堆内存中对象,不回收数据库连接、IO等物理资源。

|--失去使用价值,即为垃圾:当一个对象不再被引用的时候,就称为垃圾。

|--无法控制:垃圾回收的时间无法控制,系统会在“合适的时间”进行垃圾回收。

|--强制回收:System.gc():通知系统进行垃圾回收,但是系统是否回收还是不确定。

GC算法:

  • 根搜索算法:设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的

  • 标记-清除(Mark-Sweep)算法:标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。(未被标记的对象就是垃圾对象);清除阶段,清除所有未被标记的对象。

垃圾收集器(G1):

Garbage First。比较新的的垃圾回收技术。JDK7时引入,弱化分代,强调分区。G1算法将堆划分为若干个区域(Region),清理垃圾时有类似于硬盘整理的操作,不会有碎片问题。

finalize()方法:

  • 对象被销毁之前调用。
  • finalize方法由垃圾回收机制调用,因此调用情况具有不确定性。
  • 当JVM执行finalize()时出现了异常,垃圾回收机制不会报告异常,程序继续执行。
public class Test垃圾回收 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Garbage(i);
}
// 强制垃圾回收
System.gc();
}
}
class Garbage {
private int id;
public Garbage(int id) {
this.id = id;
}
@Override
protected void finalize() throws Throwable {
System.out.println("被回收:" + id);
}
}

被回收:6

被回收:1

被回收:0

被回收:4

被回收:3

被回收:2

被回收:9

(↑每次执行结果不一样)

对象的引用

强引用(StrongReference)。

软引用(SoftReference):内存不足时会被回收。可用于实现缓存。

弱引用(WeakReference):不管内存够不够,都会被回收。弱引用可以用于构建非敏感区域的缓存。

import java.lang.ref.WeakReference;
// 弱引用(WeakReference):不管内存够不够,都会被回收。
// 弱引用可以用于构建非敏感区域的缓存。
public class TestWeakReference {
public static void main(String[] args) throws Exception {
String str = new String("圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。");
// 弱引用:当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。
WeakReference<String> wr = new WeakReference<String>(str);
str = null;
// get():获取被引用的对象
System.out.println("弱引用:" + wr.get());
System.out.println(wr.isEnqueued());
// 强制垃圾回收
System.gc();
// 再次取出弱引用的对象
System.out.println("弱引用:" + wr.get());
System.out.println(wr.isEnqueued());
}
}
弱引用:圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。
false
弱引用:null
false

虚引用(PhantomReference):虚引用必须和引用队列(ReferenceQueue)联合使用,主要用于跟踪被垃圾回收的状态。(phantom:幻影、错觉)

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
// 虚引用(PhantomReference):
// 虚引用必须和引用队列(ReferenceQueue)联合使用,
// 主要用于跟踪被垃圾回收的状态。(phantom:幻影、错觉)
public class TestPhantomReference {
public static void main(String[] args) throws Exception {
String str = new String("圣僧东土到此,有些什么人事送我们?快拿出来,好传经与你去。");
// 引用队列
ReferenceQueue refQue = new ReferenceQueue();
PhantomReference pRef = new PhantomReference(str, refQue);
str = null;
// 虚引用的get()不到,结果为null
System.out.println("虚引用:" + pRef.get());
;
System.out.println("---强制垃圾回收---");
System.gc();
System.runFinalization();// 通知系统进行系统清理
// 垃圾回收之后,虚引用将被放入引用队列中
System.out.println("refQue.poll():" + (refQue.poll() == pRef));
}
}
虚引用:null
---强制垃圾回收---
refQue.poll():true

直接内存

堆外内存,直接受操作系统管理。

作用:

(1)减少垃圾回收

(2)提升IO效率

java.nio.ByteBuffer.allocateDirect(capacity);

import java.nio.ByteBuffer;
//“直接内存”VS“堆内存”
// 直接内存分配慢:当频繁申请到一定量时尤为明显
// 直接内存读写块:在多次读写操作的情况下差异明显
public class ByteBufferCompare {
public static void main(String[] args) {
// 分配比较(100万次已看出明显差别)
compareAllocate(100_0000L, "直接内存");
compareAllocate(100_0000L, "堆内存");
// 读写比较(1亿次可看出差别)
compareIo(1_0000_0000L, "直接内存");
compareIo(1_0000_0000L, "堆内存");
}
// 分配空间比较
public static void compareAllocate(long times, String memoryType) {
// // 操作次数
long _start = System.currentTimeMillis();
ByteBuffer buffer = null;
for (int i = 0; i < times; i++) {
if ("直接内存".equals(memoryType)) {
buffer = ByteBuffer.allocateDirect(2);
} else {
buffer = ByteBuffer.allocate(2);
}
}
long _end = System.currentTimeMillis();
System.out.println(times + "次内存分配:" + memoryType + ":"
+ (_end - _start));
}
// 读写性能比较
public static void compareIo(long times, String memoryType) {
// 先分配空间
ByteBuffer buffer = null;
int capacity = 2 * (int) times;
if ("直接内存".equals(memoryType)) {
buffer = ByteBuffer.allocateDirect(capacity);
} else {
buffer = ByteBuffer.allocate(capacity);
}
// 再测试读写时间
long _start = System.currentTimeMillis();
for (int i = 0; i < times; i++) {
// putChar(char value) 用来写入 char 值
buffer.putChar('a');
}
// 将缓存字节数组的指针设置为数组的开始序列(即数组下标0)
buffer.flip();
for (int i = 0; i < times; i++) {
buffer.getChar();
}
long _end = System.currentTimeMillis();
System.out.println(times + "次读写:" + memoryType + ":" + (_end - _start));
}
}
100 0000次内存分配:直接内存:459
100 0000次内存分配:堆内存:15 1 0000 0000次读写:直接内存:174
1 0000 0000次读写:堆内存:290

Java基础教程——垃圾回收机制的更多相关文章

  1. java基础之 垃圾回收机制

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...

  2. java中存在垃圾回收机制,但是还会有内存泄漏的问题,原因是

    答案是肯定的,但不能拿这一句回答面试官的问题.分析:JAVA是支持垃圾回收机制的,在这样的一个背景下,内存泄露又被称为“无意识的对象保持”.如果一个对象引用被无意识地保留下来,那么垃圾回收器不仅不会处 ...

  3. JVM基础(5)-垃圾回收机制

    一.对象引用的类型 Java 中的垃圾回收一般是在 Java 堆中进行,因为堆中几乎存放了 Java 中所有的对象实例.谈到 Java 堆中的垃圾回收,自然要谈到引用.在 JDK1.2 之前,Java ...

  4. jvm基础知识—垃圾回收机制

    1.首先类的实例化.static.父类构造函数执行顺序 我们来看下面的程序代码: public class A { int a1 = 8; { int a3 = 9; System.out.print ...

  5. 【java虚拟机】垃圾回收机制详解

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6486852.html 一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分 ...

  6. Java中的垃圾回收机制

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...

  7. Java语言的垃圾回收机制

    java语言从诞生开始,一个吸引人眼球的功能就是垃圾回收,想一想C++中时不时的内存泄漏,当时感觉写java代码直是一种享受呀.     和.NET的引用计数不同,java的垃圾回收机制采取的是有向图 ...

  8. JAVA中的垃圾回收机制以及其在android开发中的作用

    http://blog.csdn.net/xieqibao/article/details/6707519 这篇文章概述了JAVA中运行时数据的结构,以及垃圾回收机制的作用.在后半部分,描述了如何检测 ...

  9. Java中的垃圾回收机制&内存管理&内存泄漏

    1. Java在创建对象时,会自动分配内存,并当该对象引用不存在的时候,释放这块内存. 为什么呢? 因为Java中使用被称为垃圾收集器的技术来监视Java程序的运行,当对象不再使用时,就自动释放对象所 ...

随机推荐

  1. Mybatis---05Mybatis配置文件浅析(三)

    1.objectFactory:(对象工厂)MyBatis 每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成. 默认的对象工厂需要做的仅仅是实例化目标类,要么 ...

  2. Git系列:常用命令

    一.背景 作为一名程序员,怎么能不懂Git那些常用命令呢?于是花费一点时间来总结Git命令.关于安装的话,就不讲了. 二.常用命令 1.配置全局的用户名称和用户邮箱 git config --glob ...

  3. 使用MQTT协议的4G DTU模块具有什么优势

    什么是MQTT协议 要了解使用MQTT协议的4G DTU模块具有哪些优势,首先我们需要了解什么是MQTT协议,MQTT协议最早是IBM开发的一个即时通讯协议,它的主要是为大量计算能力有限且工作在低带宽 ...

  4. UbuntuStudio20.04安装教程(双系统安装,windows10已安装)

    硬件和系统: acer4750(原i3换i7,加固态硬盘200多G,原机械硬盘500G由光驱改装,内存由2G增加为6G)2010年购买3300,性价比高,硬件升级后2020年不过时 windows10 ...

  5. MySQL图形界面客户端

    图形界面客户端 使用图形界面客户端操作数据库更直观.方便.下面三个客户端都能操作MySQL,各有各自的优点. 1.Navicat Premium 下载安装包下载 关注公众号[轻松学编程],然后回复[n ...

  6. pandas模块常用函数解析之Series(详解)

    pandas模块常用函数解析之Series 关注公众号"轻松学编程"了解更多. 以下命令都是在浏览器中输入. cmd命令窗口输入:jupyter notebook 打开浏览器输入网 ...

  7. nacos、ribbon和feign的简明教程

    nacos简明教程 为什么需要nacos? 在微服务架构中,微服务之间经常要相互通信和调用,而且一个服务往往存在多个实例来降低负荷或保证高可用.我们假定A服务要调用B服务,最简单的方式把B服务的地址和 ...

  8. 题解 P1541 【乌龟棋】

    题目描述 乌龟棋的棋盘是一行\(N\)个格子,每个格子上一个分数(非负整数).棋盘第\(1\)格是唯一的起点,第\(N\)格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点. 乌龟棋中\(M\) ...

  9. 2.1获取Git仓库-2.2记录每次更新到仓库

    2.1 获取 Git 仓库 获取 Git 仓库通常有两种方式 将尚未进行版本控制的本地目录转换为 Git 仓库: 从其它服务器 克隆 一个已存在的 Git 仓库. 在已存在目录中初始化仓库 首先进入该 ...

  10. 搭建面向NET Framework的CI/CD持续集成环境(一)

    前言 网上大多数都是针对主流的Spring Cloud.NET Core的CI/CD方案.但是目前国内绝大部分的公司因为一些历史原因无法简单的把项目从NET Framework切换升级到NET Cor ...