出来混的,总是要还的。看来做软件,写代码也是这样啦!这篇应该算是Java编程思想阅读笔记的续集,由一段写得非常垃圾的程序引起,牵出了垃圾回收等一些相关知识,至于原来程序出现的堆溢出(java.lang.OutOfMemoryError: Java heap space)原因,还得继续寻找。下面先看一段类似的垃圾代码:
- package com.javatest.gc.lixuan;
-
- import java.lang.ref.SoftReference;
-
- public class GCTest {
- public static void main(String[] args) {
- final int MAX_THREAD_NUM = 20;
- int threadTotalNum = 0;
- for (; threadTotalNum < MAX_THREAD_NUM; threadTotalNum++) {
- NewThread nt = new NewThread();
- NewThread.setThreadNum();
- nt.start();
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
-
- e.printStackTrace();
- }
- }
-
- }
-
- }
-
- class NewThread extends Thread {
- public static Integer threadNum = 0;
- public int mNum = 0;
- private int mStringBuilderNum = 0;
- private String str = "nihao!";
-
- public NewThread() {
- synchronized (NewThread.threadNum) {
- mNum = threadNum;
- }
- }
-
- public void run() {
- while (true) {
- try {
- int n = 10000;
- StringBuilder[] sb = new StringBuilder[n];
- SoftReference<StringBuilder[]> sf = new SoftReference<StringBuilder[]>(sb);
- for (int i = 0; i < n; i++) {
- sb[i] = new StringBuilder();
- sb[i].append(str);
- Thread.sleep(10);
- System.out.println("Thread number:" + mNum);
- }
- System.out.println("Thread number:" + mNum +"("+this.getId()+")"+ " new sb numbers:" + mStringBuilderNum++);
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public static void setThreadNum() {
- synchronized (threadNum) {
- threadNum++;
- }
- }
- }
首先说明代码,一个线程类型(NewThread),就是在死循环中不停的创建新对象,当然里面标识了线程号;另一个类就是main所在了,循环创建一定数量的NewThread对象,然后启动。初衷是想建立一定数量的线程,让线程循环执行,结果其实忽略了几个问题:
1.线程对象是在循环体中创建的,那其作用域的问题;
2.线程创建完成后,main函数也就是主线程运行完毕了
针对第一个问题就是今天记录的主题,Java中的垃圾回收机制。先从《Java编程思想》中汲取,有C/C++的基础,有时候并不见得是好事,在C/C++中总会想着函数返回时内存的回收,动态申请的内存要主动释放,而且new申请的对象会在释放时自动调用析构函数;而在Java中不用过多的考虑,但是也放心不下,垃圾收集器什么时候,回收怎样的对象占用的内存呢?Java是在堆上分配对象,采用一些回收方法,目标是把不会再用到的对象内存释放掉,当然它没有那么聪明,知道你以后不会再用哪些,一般便于理解说明的是“引用计数”方式,即每个对象都含有一个引用计数器,当有引用指向对象时,引用数加1,当引用离开作用域或被置null时,引用计数减1,当运行的后台回收线程发现某个对象引用为0时,就释放其内存,这里有个问题是如果有循环引用(还有我上面那个程序你会发现问题),那么就无法正确释放内存;因此又有了“停止——复制”方式,这种方式是先暂停程序的运行,然后将所有存活的对象从当前堆复制到另一个堆中,没有被复制的全部都是垃圾,而且这种方式能够使新堆保持紧凑,但是这种方式消了较低,一方面暂停了程序运行,至少比实际需要多一倍的空间,另一方面,在程序进入稳定状态后,可能只有少量或没有垃圾,如此垃圾回收就显得浪费;其它还有些方式,可以查看参考【1】。
那么如此,就有个疑问了,我的main所在的类中声明的线程类型对象,是在for循环当中,相当于每次都离开了作用域,会不会for循环完之后就都退出了呢?而且在C/C++中,main的退出意味着程序的退出,那么这个程序是不是才刚创建完所有线程就退出了呢?我们再看Java的守护线程和非守护线程,
守护线程通常是由虚拟机自己使用的,比如执行垃圾收集任务的线程;
Java程序可以把它任何创建的线程标记为守护线程;
Java初始线程(即开始于main方法的线程)是非守护线程;
只要还有任何非守护线程在运行,那么这个Java程序也在运行,即这个JVM实例还存活着;当JVM中的所有非守护线程都终止时,JVM实例将自动退出;(参考【2】)
好了,顺带的第2个问题也知道了,那么堆溢出是怎么回事呢?貌似这里不会产生啊,可以看到其使用情况(VisualVM好用的软件啊)截图如下:
垃圾回收器及时收回内存。有无休眠直接影响CPU的占用。后图多了个软引用,可以看到回收的延迟。
从代码中还看到使用了SoftReference,这个其实就是三种引用:弱引用、软引用、虚引用;大概意思就是弱引用可以再对象置null时和垃圾回收之前延长点时间再回收,和finalize类似,只是finalize中包含了回收前执行的方法(主要是在调用了C/C++中的代码要执行的内存释放);软引用多用于缓冲区,在内存告急时才会被释放;虚引用则是主要用来跟踪对象被垃圾回收的活动,和引用队列(ReferenceQueue)联合使用,在回收前做点操作(上面只是试了软引用,从截图也能看出些东西来,详细的可以看参考3)。但是这样堆溢出还是没有找到原因,还是继续寻找吧。参考:【1】详细介绍Java垃圾回收机制 http://www.cnblogs.com/laoyangHJ/articles/java_gc.html【2】Java虚拟机学习笔记(三)Java虚拟机 http://diecui1202.iteye.com/blog/606046【3】Java基础 之软引用、弱引用、虚引用 http://www.cnblogs.com/blogoflee/archive/2012/03/22/2411124.html
分享到:
相关推荐
接下来,课程将详细介绍Java在各种应用领域中的广泛使用,比如企业级软件开发、动态网页设计、数据库编程等,进而引出Java所具备的众多特点,包括简单性、面向对象、分布式处理、健壮性、结构中立、安全性、可移植性...
接着,课程回顾了计算机语言的发展历程,从机器语言、汇编语言到面向过程和面向对象的语言,最后引出Java,一种具有组件化和跨平台能力的语言。 Java的历史部分讲述了Java的起源,起始于1991年的Set-top box项目,...
由Java语言与C/C++对象在内存管理方式的不同,引出了Java语言的优势技术——垃圾处理技术。通过对GC工作原理的阐述及对一些传统的垃圾收集器的分析,提出了一种新的垃圾处理算法,一定程度上改善和提高了Java垃圾...
一个Java程序的开发过程 一个简单的Java应用程序的开发过程 什么是JSP 授课目的: 掌握Java语言的特点 掌握环境变量的配置 掌握Java程序的开发过程 了解JSP技术 授课重点及难点: 建立Java...
* 不可回收垃圾:生活中常见的不可回收垃圾,如餐巾纸、一次性筷子等。 * 有害垃圾:有毒、有害的垃圾,如电池、药品包装等。 知识点三:环保意识 * 环保的重要性:保护环境、维护生态系统、保障人类健康。 * 环保...
这就引出了一个问题:如何将用Java编写的程序转化为Windows用户友好的.exe格式?这就是exe4j这个工具的用途所在。 **exe4j简介** exe4j是由ej-technologies公司开发的一款强大的Java程序转换工具,它的主要功能是...
Java的可移植性、面向对象的设计、健壮的库集合和垃圾回收机制使得它成为开发服务器端应用程序的理想选择。Java EE(Java Platform, Enterprise Edition)为构建企业级应用程序提供了一整套服务和API。这包括用于...
12. **JVM**:理解Java虚拟机的工作原理,包括内存管理(堆、栈、方法区等)、垃圾回收机制和性能优化技巧。 13. **设计模式**:学习常见的设计模式,如单例、工厂、装饰器、观察者等,提升代码的可维护性和可扩展性...
通过分类的实践活动,孩子们认识到了可回收垃圾、厨余垃圾、有害垃圾和其他垃圾分别应该投入何种颜色的垃圾桶内。 游戏环节是整个活动的高潮,孩子们在“送垃圾宝宝回家”的游戏活动中,亲手将模拟的垃圾放入对应...
* 通过讨论学生板演的结果,师生合作完成垃圾种类的划分:可回收垃圾、不可回收垃圾和有害垃圾。 * 让学生了解到垃圾回收利用的好处和重要性。 四、垃圾的处理方法 * 可回收垃圾的处理:主要处理方法是把可回收...
(类的加载概述和加载时机) (类加载器的概述和分类) (获取class文件对象的三种方式) ...(通过反射写一个通用的设置某个对象的某个属性为指定的值) (通过用户的增删改查和学生的登录注册引出中介) (动态代理的概述和实现)
第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载JDK 4 1.2.2 安装JDK 5 ...
2. **数据迁移**:当需要将数据从一个环境迁移到另一个环境时,模板的引入引出功能提供了便捷的方式。 3. **数据交换**:不同部门之间或者与其他企业之间的数据交换可以通过模板的格式进行标准化处理。 #### 三、...
例如,哪些是可回收垃圾,哪些是不可回收垃圾,以及有害垃圾的分类处理方法。短片内容生动有趣,不仅吸引了幼儿的注意力,同时也使垃圾分类的知识更加容易为幼儿所接受和记忆。 为了巩固学习效果,教案中设计了名为...
这就引出了我们的主题——"java反编译软件 class转java"。 反编译是将已编译的机器代码转换回源代码的过程。在Java世界里,这个过程就是将.class文件转换回.java文件。这样的工具可以帮助开发者查看和理解已有的...
在Java程序设计课程中,可以通过一个具体的程序功能或问题,引出学习的主题,让学生理解编程可以解决现实问题,从而激发学生的求知欲望。 “目标”阶段明确告诉学生本节课的具体学习目标。在Java课程中,这可能包括...
第1章 让自己的第一个Java程序跑起来 2 教学视频:19分钟 1.1 想要用Java改变这个世界吗? 2 1.1.1 Java有什么优势? 2 1.1.2 Java在哪儿? 3 1.2 准备好开始Java之旅 3 1.2.1 下载JDK 4 1.2.2 安装JDK 5 ...
然而,Smali代码对于非专业人士来说,阅读和理解起来相当困难,这就引出了Smali2Java工具的出现。 Smali2Java的核心功能在于将Smali代码转换为Java源代码。这个过程极大地简化了逆向工程师的工作,因为Java代码对于...