开辟内存
启动一个Java程序就会启动一个JVM进程
在Java程序中需要开辟内存空间是,需要向JVM申请
当JVM预先划分的内存尚未使用完时,就直接从JVM预先划分的内存中开辟空间
当JVM预先划分的内存空间被使用完时,JVM就会像操作系统申请
如何JVM申请的内存达到上限,就会通知Java程序内存溢出
/
1、在 Windows 命令提示符 或 Linux 终端 中输入 jconsole 可以启动 “Java监视和管理控制台”
2、在 “Java监视和管理控制台” 中 可以连接指定的 JVM 进程,从而了解 JVM 的运行状况
*/
public class GarbageCollectionTest1 {
public static void main(String[] args) {
System.out.println( “main begin” );
while( true** );
// System.out.println( “main end” ); // Unreachable code
}
}
垃圾回收
当JVM管理内存中的“无用”对象时,该对象占用的内存应该被回收
如果“无用”对象一直不被回收,则该对象会一致驻留内存、导致该内存区域无法被重复使用
JVM中提供了专门用于回收无用对象的所占内存的线程,被称作 垃圾回收线程
垃圾回收的本质实在回收内存 垃圾回收器将无用对象所占的内存释放出来的过程,就是所谓的垃圾回收
如果因为某些原因导致无法回收所占用对象的内存,则会导致 内存泄漏
程序员可以在Java程序中向JVM建议执行垃圾回收操作
程序员只有建议权没有让GC立即执行的权限
通过Runtime.getRuntime().gc()实现
通过System.gc()实现
**
回收依据
当某个对象不再被任意一个引用变量所引用时,该对象所占用的内存就可以被回收了
当某个类不在被使用时,该类就可以卸载了,它所占用的内存就被回收了
Runtime
作用
每个Java应用程序都有一个Runtime类实例
通过Runtime类的实例使应用程序能够与其运行的环境相连接
Java应用程序中不能创建自己的Runtime类实例
类方法
public static Runtime getRuntime()
实例方法
public int availableProcessors()//此方法返回到虚拟机的最大可用的处理器数量
public long totalMemory()//方法返回存储器中的Java虚拟机的总量
public long freeMemory()//方法返回存储器中的Java虚拟机的剩余量
public long maxMemory()//方法返回Java虚拟机将尝试使用的最大内存量。
// 如果没有固有限制,则返回值Long.MAX_VALUE。
public void gc()
public void exit(int status)//正常退出status为0,非正常则为非0
public Process exec(String command)throws IOException//执行某个进程
public static void main(String[] args) {
// 获取 与 当前 Java 应用程序相关的 运行时 ( Runtime ) 对象<br /> **Runtime** runtime = **Runtime**.getRuntime();
// availableProcessors 方法用于 向 Java 虚拟机返回可用处理器的数目<br /> **int** p = runtime.availableProcessors(); // 注意是 "虚拟处理器" 个数<br /> **System**.out.println( p );
**long** total = runtime.totalMemory();// 返回 Java 虚拟机中的内存总量<br /> **long** max = runtime.maxMemory() ; // 返回 Java 虚拟机试图使用的最大内存量<br /> **long** free = runtime.freeMemory() ; // 返回 Java 虚拟机中的空闲内存量<br /> **System**.out.println( total + "Bytes , " + max + "Bytes , " + free + "Bytes");
**Runtime** rt = **Runtime**.getRuntime();<br /> **System**.out.println( runtime == rt ); // true
}
使用Runtime实例的exit方法终止虚拟机
public class GarbageCollectionTest3 {
public static void main(String[] args) {
**System**.out.println( "main begin" );
// 获取 与 当前 Java 应用程序相关的 运行时 ( Runtime ) 对象<br /> **Runtime** runtime = **Runtime**.getRuntime();
// 通过启动虚拟机的关闭序列,终止当前正在运行的 Java 虚拟机<br /> runtime.exit( 0 ); // 根据惯例,非零的状态码表示非正常终止
**System**.out.println( "main end" );
}<br />}
通过Runtime实例的exec方法执行指定命令
import java.io.IOException;
/
1、使用 Runtime 实例的 exec 放可以执行指定的命令
2、可以尝试使用 Java 程序 让自己的 Windows 系统 注销/关闭/重启
*/
public class GarbageCollectionTest4 {
public static void main(String[] args) throws IOException** {
**System**.out.println( "main begin" );
// 获取 与 当前 Java 应用程序相关的 运行时 ( Runtime ) 对象<br /> **Runtime** runtime = **Runtime**.getRuntime();
//runtime.exec( "notepad" );// 在 Windows 环境下会执行 C:\Windows\notepad.exe <br /> //runtime.exec( "mspaint" );// 在 Windows 环境下会执行 C:\Windows\System32\mspaint.exe <br /> runtime.exec( "jconsole" );// 运行 JAVA_HOME 下 bin 目录中的 jconsole 命令
**System**.out.println( "main end" );
}<br />}
使用Runtime实例的gc()方法建议垃圾回收器回收垃圾
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/
使用 Runtime 实例的 gc 方法向 JVM 建议 回收垃圾
/
public class GarbageCollectionTest5 {
public static void main(String[] args) throws IOException** {
**Runtime** runtime = **Runtime**.getRuntime();<br /> show( runtime );
**List**<**String**> list = **new** **ArrayList**<>();
**String** s = "" ;
**for**( **int** i = 0 ; i < 10000 ; i++ ) {<br /> s += i ;<br /> list.add( s );<br /> }
show( runtime );
s = **null** ;<br /> list = **null** ;
// 建议 垃圾回收器 执行 垃圾回收操作<br /> **runtime.gc();**
show( runtime );
}
**public** **static** **void** **show**( **Runtime** runtime ) {<br /> **long** total = runtime.totalMemory();<br /> **long** free = runtime.freeMemory() ;<br /> **System**.out.println( "总内存 " + total + " Bytes , 空闲内存 " + free + " Bytes");<br /> **System**.out.println( "已使用 " + ( total - free ) + " Bytes.");<br /> }<br />}
让线程睡眠以便于通过Java监视和管理控制台连接到相应的JVM进程
配合 jconsole 可以启动 “Java监视和管理控制台”使用
import java.util.ArrayList;
import java.util.List;
/
1、使用 Thread.sleep( long ) 方法可以让当前的线程睡眠
2、线程睡眠时即可通过 jconsole 来启动 “Java监视和管理控制台” 并连接到该程序对应的 JVM 进程
*/
public class GarbageCollectionTest6 {
public static void main(String[] args) throws InterruptedException** {
**System**.out.println( "JVM启动" );
**Thread**.sleep( 20000 ); // 让当前线程(main)睡眠 (以毫秒为单位)
**System**.out.println( "开始创建对象" );
**List**<**String**> list = **new** **ArrayList**<>();
**String** s = "" ;
**for**( **int** i = 0 ; i < 10000 ; i++ ) {<br /> s += i ;<br /> list.add( s );<br /> }
**Thread**.sleep( 15000 ); // 让当前线程(main)睡眠 (以毫秒为单位)
**System**.out.println( "准备垃圾回收" );
s = **null** ;<br /> list = **null** ;
// 建议 垃圾回收器 执行 垃圾回收操作<br /> **System**.gc();
**System**.out.println( "垃圾回收后" );
**Thread**.sleep( 150000 );
}<br />}
强引用
形式
List
array[…]=”hello”
回收
当某个对象存在强引用时,垃圾回收器不会回收该对象占用的内存
即使内存十分紧张或不够使用,也不会回收强引用所关联的对象
类型
没有与之对应的类型
import java.util.ArrayList;
import java.util.List;
public class ReferenceTest1 {
public static void main(String[] args) {
**RuntimeHelper**.gc();<br /> **RuntimeHelper**.showMemory();
**String** s = **new** **String**( "hello" );<br /> **List**<**String**> list = **new** **ArrayList**<>();<br /> list.add( s );
**String**[] array = **new** **String**[ 10 ];<br /> array[ 0 ] = s ;
**RuntimeHelper**.gc();<br /> **RuntimeHelper**.showMemory();
// 去除强引用<br /> s = **null**;<br /> list = **null** ;<br /> array[ 0 ] = **null** ;<br /> array = **null** ;
**RuntimeHelper**.gc();<br /> **RuntimeHelper**.showMemory();<br /> }<br />}
软引用
形式
SoftReference
softRef.get()
回收
适用于内存敏感的环境下
当内存充足时不会回收拥有 软引用 的对象占用的内存
类型
Java.lang.ref.SoftReference
import java.lang.ref.SoftReference;
import java.util.ArrayList;
public class ReferenceTest2 {
public static void main(String[] args) {
**RuntimeHelper**.gc();<br /> **RuntimeHelper**.showMemory();
// 使用 强引用 关联一个 ArrayList 实例<br /> **ArrayList**<**String**> list = **new** **ArrayList**<>();
// 创建一个 软引用 ( Soft Reference ) ,它关联了 list 变量所引用的对象<br /> **SoftReference**< **ArrayList**<**String**> > softRef = **new** **SoftReference**<>( list );
list = **null** ; // 取消对新创建的 ArrayList 实例的强引用
// 因为将 软引用关联的对象直接赋值给了 list 变量,所以 list 变量是 ArrayList 实例的强引用<br /> list = softRef.get(); // 通过 SoftReference 实例的 get 方法可以获取 软引用 所关联的对象<br /> **for**( **int** i = 0 ; i < 59000 ; i++ ) {<br /> list.add( **new** **String**( i + "" ) );<br /> }
list = **null** ;
**RuntimeHelper**.gc(); // 可以通过 增加 或 删除 这行代码来对比<br /> **RuntimeHelper**.showMemory();<br /> }<br />}
弱引用
形式
WeakReference
softRef.get()
回收
适用于内存更敏感的环境下
不管内存是否充足都会回收拥有 若引用 的对象占用的内存
类型
Java.lang.ref.WeakReference
import java.lang.ref.WeakReference;
import java.util.ArrayList;
public class ReferenceTest3 {
public static void main(String[] args) {
**RuntimeHelper**.gc();<br /> **RuntimeHelper**.showMemory();
// 使用 强引用 关联一个 ArrayList 实例<br /> **ArrayList**<**String**> list = **new** **ArrayList**<>();
// 创建一个 弱引用 ( Weak Reference ) ,它关联了 list 变量所引用的对象<br /> **WeakReference**< **ArrayList**<**String**> > weakRef = **new** **WeakReference**<>( list );
list = **null** ; // 取消对新创建的 ArrayList 实例的强引用
// 因为将 弱引用关联的对象直接赋值给了 list 变量,所以 list 变量是 ArrayList 实例的强引用<br /> list = weakRef.get(); // 通过 WeakReference 实例的 get 方法可以获取 弱引用 所关联的对象
**for**( **int** i = 0 ; i < 59000 ; i++ ) {<br /> list.add( **new** **String**( i + "" ) );<br /> }
**RuntimeHelper**.showMemory();
list = **null** ;
**RuntimeHelper**.gc(); // 可以通过 增加 或 删除 这行代码来对比<br /> **RuntimeHelper**.showMemory();<br /> }<br />}
虚引用
作用
又叫幽灵引用,基本没有引用
用于追踪垃圾回收过程
通常结合ReferenceQueue使用
类型
Java.lang.ref.PhantomReference
public final class RuntimeHelper {
**private** **RuntimeHelper**() {<br /> }
**public** **static** **void** **showMemory**() {<br /> **Runtime** runtime = **Runtime**.getRuntime();<br /> **long** total = runtime.totalMemory();<br /> **long** free = runtime.freeMemory() ;<br /> **System**.out.print( "总内存 " + total + " Bytes ," );<br /> **System**.out.print( "已使用 " + ( total - free ) + " Bytes ,");<br /> **System**.out.println( "空闲内存 " + free + " Bytes");<br /> }
**public** **static** **void** **gc**() {<br /> **System**.out.println( "正在向垃圾回收器建议回收垃圾" );<br /> **Runtime**.getRuntime().gc();<br /> }<br />}