- 浏览: 128419 次
- 性别:
- 来自: 北京
最新评论
-
C_J:
有必要这么鸡冻咩?
编写自己的ClassLoader知识点 -
jason61719:
你这不是说了等于没说吗……就解析个loadClass(),谁不 ...
编写自己的ClassLoader知识点 -
jiming:
tedeyang 写道很好的改进,不过话说回来,mybatis ...
开源,从关注产品社区做起(ibatis3.x的最近一个issue展示) -
C_J:
独爱Java 写道好像实际用处并不是很大,只是多了解了有这个东 ...
Java内存模型笔记 -
独爱Java:
好像实际用处并不是很大,只是多了解了有这个东西而已。。。
Java内存模型笔记
题记:
前几天讨论到WeakHashMap(这个是个弱引用的Map,用于缓存,弱引用的特点是随时被GC回收),WHM在每次put()会间接地调用expungeStaleEntries()来从去除实体。今天看到Hudon的WeakLogHandler的应用就怀着学习的目的来看看WeakRefence。(软引用在内存不足的时候被GC回收,弱引用可能在每次都被GC回收,她们的机制或原理是什么呢?我总是很好奇)
分析:
粗略看了下设计,有很多疑点不懂:
1、pending对象的用处?
2、ReferenceHandler线程什么时候notify呢?
3、到底哪些对象会被GC回收呢?
查了点资料后:http://www.ibm.com/developerworks/cn/java/i-garbage2/index.html
才有了点领悟。
“在 Java 1.2.2 中,整个引用处理发生很大的改变。其目标是平等地对待所有的引用,并以相同的方式处理它们。因此,我们实际上在堆上创建两个单独的对象 —— 对象本身和一个单独的 “引用” 对象。可选地,引用对象可以与一个队列相关联,当 referent 变得不可获得时,可以将引用对象添加到该队列中。”
所有引用都有个“引用队列”,也就是代码里的queue,ReferenceHandler 线程负责把reference入队列,如果未“标记”或者该引用没有指向任何Queue,则等待GC回收。
这里所谓的“标记”是指GC的标记阶段,也就是GC标记所有活动的对象,从效率上考虑,GC不会去标记unreachable的对象,而未“标记”的对象就是“垃圾”了。
所以作为WeakReference引用就不会被“标记”(register),从而会被GC回收掉,这点与Soft引用不同,Soft引用被标记但在内存不足的情况下,被特殊处理。
有分析不正确的地方,还请指正,也是处于学习阶段:)
弱引用Logger例子:
public final class WeakLogHandler extends Handler { private final WeakReference<Handler> target; private final Logger logger; // Logger的管理对象 public WeakLogHandler(Handler target, Logger logger) {// 典型的把管理对象传入 this.logger = logger; logger.addHandler(this);// 把干活对象加入管理对象中。 this.target = new WeakReference<Handler>(target); // 新建弱引用,且未指定queue } public void publish(LogRecord record) { Handler t = resolve(); if(t!=null) t.publish(record); } public void flush() { Handler t = resolve(); if(t!=null) t.flush(); } public void close() throws SecurityException { Handler t = resolve(); if(t!=null) t.close(); } private Handler resolve() { Handler r = target.get(); // get引用,判断是否已经被回收 if(r==null) logger.removeHandler(this); return r; } @Override public void setFormatter(Formatter newFormatter) throws SecurityException { super.setFormatter(newFormatter); Handler t = resolve(); if(t!=null) t.setFormatter(newFormatter); } }
看看小兵WeakRefence的定义:
public class WeakReference<T> extends Reference<T> { public WeakReference(T referent) { super(referent); } public WeakReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } }
看到基本共享父类Reference。(莫非JAVA引用默认就是弱引用?)
看看Reference类定义:
public abstract class Reference<T> { private T referent; /* Treated specially by GC */ ReferenceQueue<? super T> queue; // 从后面分析来看,这个就是引用队列了,被标记的引用入队列 Reference next; // 指向下一个引用 transient private Reference<T> discovered; /* used by VM */ /* Object used to synchronize with the garbage collector. The collector * must acquire this lock at the beginning of each collection cycle. It is * therefore critical that any code holding this lock complete as quickly * as possible, allocate no new objects, and avoid calling user code. */ static private class Lock { }; private static Lock lock = new Lock(); // GC线程在回收的时候的锁。 /* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. */ private static Reference pending = null; /* -- Constructors -- */ Reference(T referent) { this(referent, null); } Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue;// 弱引用就是一个NULL的引用队列 } /* High-priority thread to enqueue pending References */ private static class ReferenceHandler extends Thread {// 注意这里是static线程,且优先级最高。 ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference r; synchronized (lock) { if (pending != null) { r = pending; Reference rn = r.next; pending = (rn == r) ? null : rn; r.next = r; } else { try { lock.wait(); } catch (InterruptedException x) { } continue; } } // Fast path for cleaners if (r instanceof Cleaner) { ((Cleaner)r).clean(); continue; } ReferenceQueue q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); // 构造函数里面未指定queue,则指向NULL queue } } } static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); Thread handler = new ReferenceHandler(tg, "Reference Handler"); /* If there were a special system-only priority greater than * MAX_PRIORITY, it would be used here */ handler.setPriority(Thread.MAX_PRIORITY); handler.setDaemon(true); handler.start(); } /* -- Referent accessor and setters -- */ /** * Returns this reference object's referent. If this reference object has * been cleared, either by the program or by the garbage collector, then * this method returns <code>null</code>. 如果引用被程序或GC回收,则返回null */ public T get() { return this.referent; } /** * Clears this reference object. Invoking this method will not cause this * object to be enqueued. */ public void clear() { this.referent = null; } /* -- Queue operations -- */ /** * Tells whether or not this reference object has been enqueued, either by * the program or by the garbage collector. If this reference object was * not registered with a queue when it was created, then this method will * always return <code>false</code>. * 当前引用是否被程序或者GC入队列,如果创建的时候未注册,则返回false */ public boolean isEnqueued() { /* In terms of the internal states, this predicate actually tests whether the instance is either Pending or Enqueued */ synchronized (this) { return (this.queue != ReferenceQueue.NULL) && (this.next != null); } } /** * Adds this reference object to the queue with which it is registered, * if any. */ public boolean enqueue() { return this.queue.enqueue(this); } /* -- Constructors -- */ Reference(T referent) { this(referent, null); } Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; } }
评论
GC采用很多策略进行GC回收。其中为了消除内存碎片,采用“复制”策略:
JVM把内存拆分了3大区域,就是GC中常说的:eden、survivor、old,把eden区域“存活”的对象copy到survivor区域,然后清空eden所有内存。
另外GC根据“根搜索”策略来判断对象是否“存活”,我不确定是否跟上面提及到的ReferenceQueue有关。
希望有大大讲解下呗~
1.private static Reference pending = null;,pending对象是一个static对象,他是等待入引用队列的引用。
2.private static class ReferenceHandler extends Thread,看到ReferenceHandler其实是个静态全局线程,优先级最高,他的工作就是一发现pending引用不为NULL,就进行入引用队列操作,可以猜测,当pending不为NULL时,ReferenceHandler被吹起来。
3.其实Reference就是一个弱引用的实现,判断一个对象引用是否在引用队列里,或者说GC判断对象是否回收,靠Reference里的isEnqueued方法进行判断:
public boolean isEnqueued() { /* In terms of the internal states, this predicate actually tests whether the instance is either Pending or Enqueued */ synchronized (this) { return (this.queue != ReferenceQueue.NULL) && (this.next != null); } }
所以可以猜测每个Reference的ReferenceQueue应该在构造函数时被赋值,发现果然:
Reference(T referent, ReferenceQueue<? super T> queue) { this.referent = referent; this.queue = (queue == null) ? ReferenceQueue.NULL : queue; }
对于入引用队列的线程,有个很巧妙的设计:
r = pending; Reference rn = r.next; pending = (rn == r) ? null : rn; r.next = r;
把next重新指向pending,这样不断循环入队列。
发表评论
-
iOS入门(ongoing)
2012-09-13 11:32 1311Record it: The overview of ... -
Stuff about Android
2011-07-09 16:15 1076Foreword: long time ... -
JQuery初体验(Demo)
2011-05-22 13:43 1466Demo:Show <meta content ... -
Java内存模型笔记
2011-04-13 15:48 1545题记: 看到C/C++ ... -
Radiant_The Popular Ruby's CMS Demo篇
2011-04-02 14:49 1251题记: 上篇 记录我第一次安装Rodiant经过和 ... -
Radiant_The Popular Ruby’s CMS安装篇
2011-03-28 00:48 1287题记: 今天第一次参加JE的线下活动,robbin等 ... -
关于Azul 并发垃圾回收器
2011-03-26 14:40 1326题记: 总感觉JE讨论的帖子的东西都比较滞后,所以会 ... -
phpCMS & jQuery是我该做的(阉割了)
2011-02-27 23:02 81WD讲究以plugin挂载为结构,我需要构造一个p ... -
我的玩意:J2ME的Criteria初探
2011-01-20 21:59 1025题记: 前几天跟初中同学聊天,他问我能不能做一个GP ... -
编写自己的ClassLoader知识点
2011-01-13 14:41 1876题记: 看到InfoQ关于ClassLoader的文 ... -
周末好玩,用短信控制你的计算机
2011-01-10 16:34 3008Snapshot: 详情 ... -
About Dock Plugin on Mac
2010-11-21 22:47 1470题记: 第一次接触MAC的开发..... ... -
可变hashcode的隐患和序列化安全
2010-10-25 00:55 1380可变hashcode的隐患 为识别对象,JDK ... -
体验OSGi(helloworld.jar)—富app的热拔插
2010-10-18 23:22 2449记得以前工作的时候,有天direct manager问 ... -
MongoDB on DAO with Java Language
2010-08-26 19:17 1438A Quick Tour Using the Java d ... -
Getting Start on Mongodb
2010-08-26 01:29 1523题记: 最近老和同学聊到non-relational ... -
Java Media Framework本地玩转摄像头
2010-08-04 00:57 17491、简介The JavaTM Media Framework ... -
《重构》读书笔记
2010-05-09 00:05 1054Martin Fowler于2003年出版 ... -
RPC之WebServices&RMI&JMS,phprpc框架?(待续)
2010-05-06 22:31 55前段时间写过基本的WebServices,也没再做深入 ... -
Java应用中的SQL注入攻击和防范
2010-04-24 01:06 6729说说自己对注入的 ...
相关推荐
Java队列模拟实现是一个典型的计算机科学中的数据结构应用,它主要涉及了Java编程语言和队列数据结构。在这个工程中,开发者已经创建了一个基于图形用户界面(GUI)的应用程序,用于演示和操作队列的各种功能。以下...
在实际应用中,Java提供了一些内置的队列接口和类,如Queue、Deque、ArrayDeque等,它们提供了上述操作的实现。开发者可以根据具体需求选择合适的数据结构和实现方式。例如,如果需要高效访问元素,可以选择...
Java 引用队列和虚引用实例分析 Java 引用队列和虚引用是 Java 语言中两种重要的引用类型,它们在程序中扮演着不同的角色。引用队列由 `ReferenceQueue` 类表示,用于保存被回收后对象的引用,而虚引用则是弱引用的...
在Java中,我们可以使用数组来实现优先队列。这篇文章将探讨如何利用数组实现优先队列,并通过提供的`PriorityQ.java`文件来深入理解其实现原理。 1. **优先队列基本概念** 优先队列是一种数据结构,它维护了一个...
本文将深入探讨Java如何与MSMQ进行交互,以及创建消息队列的详细步骤。 首先,我们需要理解消息队列的基本概念。消息队列是一种中间件,它允许应用程序之间通过发送和接收消息进行通信,而无需直接调用对方。消息...
在Java编程语言中,阻塞队列是一种线程安全的数据结构,它在多线程并发控制中发挥着重要作用。阻塞队列的核心特性是当队列为空时,尝试获取元素的线程会被阻塞,直到其他线程添加元素;同样,当队列满时,试图插入...
6. **生产者-消费者模型**:队列常被用作生产者-消费者问题的解决方案,其中生产者线程将数据放入队列,而消费者线程则从队列中取出数据。`BlockingQueue`在这类场景下非常有用。 7. **JMS(Java Message Service)...
在Java中,为了更好地管理对象的生命周期,从JDK 1.2开始引入了四种不同级别的引用类型:强引用、软引用、弱引用和虚引用。每种引用类型都有其特定的应用场景,通过灵活运用这些引用类型,开发者可以在内存管理和...
在这个Java队列实现的数据结构作业练习中,我们将会探讨如何使用Java来创建一个简单的队列,并分析`Queue.java`和`Node.java`这两个文件可能包含的内容。 首先,`Queue.java`很可能是实现队列接口或类的文件。在...
描述中提到的“java android”表明这个示例可能特别针对Android环境下的Java开发,这意味着队列可能被用来解决Android应用中的特定问题,例如管理UI线程与后台任务之间的通信,或者实现高效的消息传递机制。...
消息队列(Message Queue)则是一种异步通信机制,它允许应用程序将消息发送到队列,然后由消费者在合适的时间从队列中取出并处理。这种解耦的设计使得生产者和消费者可以独立工作,提高了系统的可扩展性和稳定性。...
优先队列在Java编程中是一种特殊的数据结构,它遵循特定的出队顺序,通常是最小元素(最小优先队列)或最大元素(最大优先队列)先出队。这种数据结构在解决各种问题时非常有用,例如任务调度、事件驱动编程、搜索...
redis 案例。包含, 队列操作, socket通信, 以及 socket 和 redis 配合 redis 案例。包含, 队列操作, socket通信, 以及 socket 和 redis 配合
JAVA 的五种引用类型及引用队列 在介绍 JAVA 的五种引用之前,先介绍一下什么是引用,以及引用和对象之间的关系 什么是引用 众所周知,JAVA 是一种面向对象的语言,在 JAVA 程序运行时,对象是存储在堆内存...
JAVA 实现延迟队列的方法是指在 JAVA 中实现延迟队列的方法,即在特定的延迟时间后触发某个事件,这种机制广泛应用于日常开发的场景中,例如用户登录之后5分钟给用户做分类推送、用户多少天未登录给用户做召回推送、...
在Java编程语言中,队列和堆栈是两种基本且重要的数据结构,它们在处理数据组织和流程控制方面起着至关重要的作用。本篇将详细解释如何在Java中创建队列和堆栈,并探讨相关的核心概念。 首先,队列是一种遵循“先进...
总的来说,自定义Java的Queue队列需要对数据结构有深入的理解,并根据具体的应用场景来设计和实现。这包括选择合适的基础数据结构(如ArrayList、LinkedList等),考虑性能和并发访问等因素,以及正确实现Queue接口...
生产者将商品添加到队列,消费者从队列中取出商品进行抢购。 通过分析和理解这个"java队列源码",开发者可以学习如何在高并发环境中构建高效且线程安全的队列,这对于优化并发性能、减少线程竞争和提高系统吞吐量至...
在Java编程中,多线程和队列是两个非常重要的概念,它们对于构建高效、可扩展的并发应用程序至关重要。队列工厂则是实现多线程间通信和任务调度的一种设计模式,它提供了一种抽象和统一的方式来创建和管理队列实例。...
本示例“java引用的demo”将深入探讨四种不同类型的引用:强引用、软引用、弱引用和虚引用。这些引用类型对于理解和优化内存管理至关重要,特别是在Android开发中,因为良好的内存管理能够提升应用性能并防止内存...