先来看一段代码:

import java.util.Arrays;
import java.util.EmptyStackException; /**
* 2014年6月28日09:31:59
* @author 阳光小强
*
*/
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INITAL_CAPACITY = 15; public Stack(){
elements = new Object[DEFAULT_INITAL_CAPACITY];
} public void push(Object obj){
ensureCapacity();
elements[size++] = obj;
} public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
return elements[--size];
} /**
* 假设长度超出了默认长度则加倍
*/
private void ensureCapacity(){
if(elements.length == size){
elements = Arrays.copyOf(elements, 2 * size + 1);
}
}
}

这段程序表面上看是没有不论什么错误的,可是它隐藏着一个“内存泄露”问题,随然每次都有pop()从栈里弹出对象,可是栈中的对象还是被引用着,所以不能够及时释放。将上面代码改动例如以下:

	public Object pop(){
if(size == 0){
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}

再来看一段代码:

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader; public class IOTest {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("test.xml");
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
if(br.ready()){
System.out.println(br.readLine());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

成功输出结果例如以下:

这段代码看似没有不论什么问题,可是却存在着内存泄露问题,我们没有关闭对应的资源

再来思考一个问题,代码例如以下:

public class IOTest {
public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
}
}
}
}

上面对象能释放吗?线程能自己主动结束吗?

在搞清楚上面问题之前,我们将上面代码进行改动,先看例如以下代码:

public class IOTest {
private String data = "阳光小强"; public static void main(String[] args) {
IOTest test = new IOTest();
/*IOTest.MyThread myThread = test.new MyThread();
myThread.start();*/
test = null; //这个对象能释放吗?
//myThread = null; //线程能自己主动结束吗?为什么?
System.gc(); //启动垃圾回收器
while(true){ }
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象销毁了");
}
}

在上面代码中我们重写了IOTest对象的finalize()方法,该方法是Object类的方法(protected),作用是当对象的垃圾回收器执行的时候回调该方法。

上面我们使用了System.gc()方法来通知垃圾回收器进行垃圾回收,执行的结果是输出了“对象销毁了".以下我们将上面代码中的凝视去掉,启动线程后再来执行一次。

public class IOTest {
private String data = "阳光小强"; public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么?
System.gc(); //启动垃圾回收器
while(true){ }
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(true){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("对象销毁了");
}
}

能够看到”对象销毁了“这句话没有被输出到控制台,说明我们创建的IOTest对象没有被销毁,在非常多书上都会说,给一个对象赋null值,这个对象就会成为无主对象,就会被垃圾回收器回收,可是为什么这个线程和IOTest对象还是存在的?假设是这种话,我们应该考虑怎样节省我们的内存?再来看一段代码:

public class IOTest {
private String data = "阳光小强"; public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么? while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
} public void testUsed(){
while(true){ }
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}

输出结果:

从上面结果中我们能够看到,仅仅有当线程结束后,线程对象和启动线程的对象才干真正的被垃圾回收器回收,所以在内部类中定义线程类,启动线程,会一直持有外部类的引用。如今我们又会产生一个疑问,是不是全部的内部类都持有外部类的引用呢?以下我们再来做个试验:

public class IOTest {
private String data = "阳光小强"; public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
//myThread.start();
test = null; //这个对象能释放吗?
//myThread = null; //线程能自己主动结束吗?为什么? while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
} public void testUsed(){
while(true){ }
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}

在上面的代码中我没有启动线程,所以此时的MyThread就能够当成一个普通的内部类了,我将外部类的引用置为空,会发现没有不论什么结果输出(说明外部类没有被销毁)

public class IOTest {
private String data = "阳光小强"; public static void main(String[] args) {
IOTest test = new IOTest();
IOTest.MyThread myThread = test.new MyThread();
//myThread.start();
test = null; //这个对象能释放吗?
myThread = null; //线程能自己主动结束吗?为什么? while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.gc(); //启动垃圾回收器
}
} class MyThread extends Thread{
private int i = 0;
@Override
public void run() {
while(i<5){
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i++);
System.out.println(data);
}
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("线程对象销毁了");
}
} public void testUsed(){
while(true){ }
} @Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("外部类对象销毁了");
}
}

我再将内部类的引用和外部类的引用都置为空,则输出了以下结果:


至少我能够从上面现象中这样觉得,全部内部类都持有外部类的引用。这个结论还有待进一步的验证。。。

感谢你对“阳光小强"的关注,我的还有一篇博文非常荣幸參加了CSDN举办的博文大赛,假设你觉的小强的博文对你有帮助,请为小强投上你宝贵的一票,投票地址:http://vote.blog.csdn.net/Article/Details?articleid=30101091

最新文章

  1. 重拾OS的实现
  2. Mysql增删改
  3. Mysql sql查询性能侦查
  4. Twitter search API
  5. P1091 合唱队形
  6. HGE游戏引擎之实战篇,渐变的游戏开场
  7. 产生library cache latch原因
  8. WVGA-维基百科
  9. FreeRTOS代码剖析
  10. JPA常用注解
  11. system进程占用80端口
  12. (详细)华为Mate7 MT7-TL00的usb调试模式在哪里开启的步骤
  13. ios手机访问H5页面中$(document).on绑定无效问题
  14. 算法工程师&lt;机器学习基础&gt;
  15. python django基础五 ORM多表操作
  16. 摘:PC客户端 XP兼容性调查
  17. luogu2774 [网络流24题]方格取数问题 (最小割)
  18. 解决Cell重用问题
  19. zookeeper安装和dubbo-admin使用
  20. JAVAWEB servlet验证登录时进行完全的非空判断防止空值登录

热门文章

  1. 在Windows如何解决下Cocos2d-x示例代码TestCpp我找不到lib问题库文件
  2. java泛型 之 入门(interface)
  3. Android采用Application总结一下
  4. Codeforces Round #FF 446 C. DZY Loves Fibonacci Numbers
  5. 具体解释java定时任务
  6. Eclipse扩展点实践之添加快捷菜单项(Command方式实现)
  7. selenium通过WebDriverWait实现ajax测试
  8. Java正則表達式演示样例
  9. 图像库---Image Datasets---OpenSift源代码---openSurf源代码
  10. Shell split character line by line