深入java面向对象五:Java的内存管理

简介:

一、 Java对象的引用种类

Java内存管理包括内存分配和内存回收, 这个动作都是由JVM自动完成,所以过多的内存分配增加了内存的消耗,且垃圾回收线程的不断运行会给后台增加压力,降低系统的性能。  

1.1  对象在内存中的状态

    · 可达状态: 当一个对对象被创建后,有一个以上的引用变量引用它,在它处于可达状态。

·可恢复状态: 如果程序中的某个对象不再有任何引用变量引用它,它将先进入可恢复状态。

· 不可达状态: 当对象的所有关联都被切断,且系统调用所有对象的finalize方法依然没有使该对象变成可达状态,它就将永远失去引用,等待被回收。



1.2 强引用

java程序创建一个对象,并把这个独享赋值给一个引用变量,这个引用变量就是强引用。

JVM是肯定不会回收强引用所引用的Java对象。


1.3 软引用

软引用需要通过SoftReference实现,对于只有软引用的对象而言,当系统的内存空间足够时,它不会被系统回收,程序也可以使用该对象;当系统的内存空间充足时,系统不会回收它。 当系统的内存空间不足时,系统将会回收它。

当程序需要大量创建某个类的新对象时,而且有可能重新访问已创建老对象时,可以充分使用软引用来解决内存紧张的问题。

class Person
{
	String name;
	int age;
	public Person(String name , int age)
	{
		this.name = name;
		this.age = age;
	}
	public String toString()
	{
		return "Person[name=" + name
			+ ", age=" + age + "]";
	}
}
public class SoftReferenceTest
{
	public static void main(String[] args) 
		throws Exception
	{
		SoftReference<Person>[] people = 
			new SoftReference[100000];
		for (int i = 0 ; i < people.length ; i++)
		{
			people[i] = new SoftReference<Person>(new Person(
				"名字" + i , (i + 1) * 4 % 100));
		}
		System.out.println(people[2].get());
		System.out.println(people[4].get());
		//通知系统进行垃圾回收
		System.gc();
		System.runFinalization();
		//垃圾回收机制运行之后,SoftReference数组里的元素保持不变
		System.out.println(people[2].get());
		System.out.println(people[4].get());
	}
}

上面程序创建了一个长度为100的SoftReference数组,程序使用这个数组来保存100个person对象,当系统内存足够时,即使系统进行垃圾回收,垃圾回收机制也不会回收这些Person对象所占的内存空间。


1.4 弱引用

弱引用与软引用有点相似,区别在于弱引用所引用对象的生存空间更短。 对于只有弱引用的对象而言,当系统的垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占内存。

public class WeakReferenceTest
{
	public static void main(String[] args) throws Exception
	{
		//创建一个字符串对象
		String str = new String("疯狂Java讲义");
		//创建一个弱引用,让此弱引用引用到"疯狂Java讲义"字符串
		WeakReference<String> wr = new WeakReference<String>(str);  //①
		//切断str引用和"疯狂Java讲义"字符串之间的引用
		str = null;      //②
		//取出弱引用所引用的对象
		System.out.println(wr.get());  //③
		//强制垃圾回收
		System.gc();
		System.runFinalization();
		//再次取出弱引用所引用的对象
		System.out.println(wr.get());  //④
	}
}

系统输出:

疯狂Java讲义
null

从上图可以看出: 此时的“疯狂Java讲义”字符串对象只有一个弱引用对象引用它,程序依然可以通过这个弱引用对象来访问该字符串常量; 但是,当启动垃圾回收机制,只有弱引用的对象就会被清理掉,系统在访问弱引用的空间,就会发现以为null,表明该对象已经被清理掉了。


与WeakReference功能类似的还有WeakHashMap,用于保存对个需要使用弱引用来引用的对象。

class CrazyKey 
{
	String name;
	public CrazyKey(String name) 
	{
		this.name = name;
	}
	//重写hashCode()方法
	public int hashCode() 
	{ 
		return name.hashCode();
	}
	//重写equals方法
	public boolean equals(Object obj) 
	{
		if (obj == this)
		{
			return true;
		}
		if (obj != null && obj.getClass() == CrazyKey.class)
		{
			return name.equals(((CrazyKey)obj).name);
		}
		return false;
	}
	//重写toString()方法
	public String toString()
	{
		return "CrazyKey[name=" + name + "]";
	}
}
public class WeakHashMapTest
{
	public static void main(String[] args) throws Exception
	{
		WeakHashMap<CrazyKey , String> map
			= new WeakHashMap<CrazyKey , String>();
		//循环放入10个key-value对
		for (int i = 0 ; i < 10 ; i++)
		{
			map.put(new CrazyKey(i + 1 + "") , "value" + (i + 11));
		}
		//垃圾回收之前,WeakHashMap与普通HashMap并无区别
		System.out.println(map);
		System.out.println(map.get(new CrazyKey("2")));
		//通知垃圾回收
		System.gc();
		//暂停当前线程50ms,让垃圾回收后台线程获得执行
		Thread.sleep(50);
		//垃圾回收后,WeakHashMap里所有Entry全部清空
		System.out.println(map);
		System.out.println(map.get(new CrazyKey("2")));
	}
}

可以看出,在垃圾回收机制前,WeakHashMap的功能与普通的HashMap并没有太大的区别,它们的功能完全相似。 而一旦垃圾回收机制被执行,WeakHashMap中的所有key-value都会被清空。



1.5 虚引用

虚引用不能单独使用,它的主要作用是跟踪对象被垃圾回收的状态,程序可以通过检查与虚引用关联的引用队列中是否包含指定的虚引用,从而了解虚引用所引用对象是否即将被回收。


二、 内存泄露

内存泄漏是指: 程序运行过程中不断的分配内存,那些不再使用的内存空间应该及时回收它们,从而保证系统可以再次使用这些内存,如果存在无用的内存没有回收回来,这就是内存泄露。



三、 内存管理技巧

1. 尽量使用直接量

2. 使用StringBuffer、StringBuilder进行字符串连接

3. 尽早释放无用对象  obj=null

4. 尽量少用静态变量

5. 避免在经常调用的方法、循环中创建java对象

for(int i=0;i<100;i++){
    Object obj = new Object(); // 避免使用
}

6. 缓存经常使用的对象

7. 尽量不要使用finalize方法

8. 考虑使用SoftReferenct引用



注: 文章内容来自《疯狂Java:突破程序员基本功的16课》, 作者: 李刚

相关文章
|
23天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
4天前
|
Java
java内存区域
1)栈内存:保存所有的对象名称 2)堆内存:保存每个对象的具体属性 3)全局数据区:保存static类型的属性 4)全局代码区:保存所有的方法定义
12 1
|
18天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
36 6
|
22天前
|
存储 缓存 安全
Java内存模型(JMM):深入理解并发编程的基石####
【10月更文挑战第29天】 本文作为一篇技术性文章,旨在深入探讨Java内存模型(JMM)的核心概念、工作原理及其在并发编程中的应用。我们将从JMM的基本定义出发,逐步剖析其如何通过happens-before原则、volatile关键字、synchronized关键字等机制,解决多线程环境下的数据可见性、原子性和有序性问题。不同于常规摘要的简述方式,本摘要将直接概述文章的核心内容,为读者提供一个清晰的学习路径。 ####
36 2
|
23天前
|
存储 安全 Java
什么是 Java 的内存模型?
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)规范的一部分,它定义了一套规则,用于指导Java程序中变量的访问和内存交互方式。
55 1
|
27天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
15 2
|
29天前
|
存储 运维 Java
💻Java零基础:深入了解Java内存机制
【10月更文挑战第18天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
31 1
|
2月前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
2月前
|
监控 安全 Java
Java Z 垃圾收集器如何彻底改变内存管理
大家好,我是V哥。今天聊聊Java的ZGC(Z Garbage Collector)。ZGC是一个低延迟垃圾收集器,专为大内存应用场景设计。其核心优势包括:极低的暂停时间(通常低于10毫秒)、支持TB级内存、使用着色指针实现高效对象管理、并发压缩和去碎片化、不分代的内存管理。适用于实时数据分析、高性能服务器和在线交易系统等场景,能显著提升应用的性能和稳定性。如何启用?只需在JVM启动参数中加入`-XX:+UseZGC`即可。
145 0
|
5月前
|
算法 Java 开发者
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
Java面试题:Java内存探秘与多线程并发实战,Java内存模型及分区:理解Java堆、栈、方法区等内存区域的作用,垃圾收集机制:掌握常见的垃圾收集算法及其优缺点
39 0
下一篇
无影云桌面