G1 알고리즘 공부

java core 2010. 8. 9. 17:46

'java core' 카테고리의 다른 글

Java option 관련  (0) 2010.08.31
java -server  (0) 2010.08.19
JDK 1.6.0 update 21 때문에 Eclipse 문제 발생  (0) 2010.08.09
Random과 SecureRandom의 차이  (0) 2010.08.05
Some Java Concurrency Tips  (0) 2010.06.11
Posted by '김용환'
,


어제 열심히 코딩 테스트하는데. helios 이클립스가 문제가 있는지. 계속 PermGen에서 OOME가 계속 나서. 이상하다 싶더라구요. 이클립스 종료도 안되구...  얼마 하지도 않았는데. Memory leak도 나더라구요.

관련해서 이클립스가 머 문제있는게 아닐까 싶어서 이클립스 문서를 찾다가 아래 문제를 발견했습니다. 흘!!

Bug 319514 - [launcher] VM argument in eclipse.ini not take in account with java 1.6u21

https://bugs.eclipse.org/bugs/show_bug.cgi?id=319514 

 

Synopsis Regression: JRE identification fails due to Oracle rebranding in java.exe

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6969236





jdk 1.6.0_update 21 버젼에서 윈도우쪽 문제가 있다고 보고되었습니다. 관련해서 Eclipse진영에서는 FAQ 문서를 통해서 3가지 중 하나를 하면 문제가 없다고 합니다.

1. jdk  1.6.0 update 20으로 다운그레이드하여 사용

2. eclipse 실행 디렉토리 밑에 eclipse.ini 파일에 -XX:MaxPermSize=256m 사용

3.32bit helios버젼에 dll 파일을 다운받아 패치

 

MaxPermSize를 조절하니 문제는 나타나지는 않더라구요.

업무에 참고하셔서 귀한 시간을 허비하지 않았으면 해서 공유드립니다~

 

-----------------------------------------------------------------------------

 

http://wiki.eclipse.org/FAQ_How_do_I_run_Eclipse%3F

Oracle/Sun VM 1.6.0_21 on Windows

The Eclipse 3.3 - 3.6 launchers for Windows have a problem with the Oracle/Sun Java VM version '1.6.0_21'.

UPDATE: The latest JDK/JRE downloads have fixed this problem, so the simplest way to resolve is to download and re-install from http://www.java.com (alternative link is http://java.sun.com/javase/downloads/index.jsp)

Before the fix was released, there were three choices to work around this:

  1. switch back to '1.6.0_20' (as of July 19, 2010 it can still be downloaded here)
  2. Change the commandline for launching or add the following line after "-vmargs" to your Eclipse.ini file:
    -XX:MaxPermSize=256m
    (Detailed instructions/examples)
  3. For 32-bit Helios, download the fixed eclipse_1308.dll and place it into
    (eclipse_home)/plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.0.v20100503

The bug itself was closed for voting and comments at 6969236 on the Java BugParade because the change causing the problems for Eclipse has been reverted, and is open for voting and comments at bug 319514 on the Eclipse Bugzilla.

 

---------------------------------------

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6969236
문제가 난 원인을 안 적어서 보내듭니다. java.exe와 javaw.exe 파일에 회사 이름을 sun에서 oracle로 바꾸었다고 합니다. eclipse에서는 그 정보를 보고 permsize를 조절하는 부분에 문제가 있었던 모양입니다. 그래서 update 21 - b07 버젼에 그 부분을 수정했다고 합니다.  
update 21 문서에 위의 내용이 추가되지 않은 release 버젼이라서 community의 항의성 글들이 많네요~

참조 : http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6969236


A DESCRIPTION OF THE PROBLEM :
Regression: With Java 1.6.0_21, the ("\\StringFileInfo\\%04x%04x\\CompanyName") has changed in the java.exe and javaw.exe programs from "Sun Microsystems, Inc" to "Oracle".

This causes a severe regression for programs that need to identify the Sun/Oracle HostSpot VM such that they know whether the "-XX:MaxPermSize" argument needs to be used or not.


'java core' 카테고리의 다른 글

java -server  (0) 2010.08.19
G1 알고리즘 공부  (0) 2010.08.09
Random과 SecureRandom의 차이  (0) 2010.08.05
Some Java Concurrency Tips  (0) 2010.06.11
Diagnosing Web Application OutOfMemoryErrors  (0) 2010.06.10
Posted by '김용환'
,


http://stackoverflow.com/questions/295628/securerandom-init-once-or-every-time-it-is-needed

Unlike the java.util.Random class, the java.security.SecureRandom class must produce non-deterministic output on each call. What that means is, in case of java.util.Random, if you were to recreate an instance with the same seed each time you needed a new random number, you would essentially get the same result every time. However, SecureRandom is guaranteed to NOT do that - so, creating a single instance or creating a new one each time does not affect the randomness of the random bytes it generates


Additionally, SecureRandom must produce non-deterministic output and therefore it is required that the seed material be unpredictable and that output of SecureRandom be cryptographically strong sequences as described in RFC 1750: Randomness Recommendations for Security.

'java core' 카테고리의 다른 글

G1 알고리즘 공부  (0) 2010.08.09
JDK 1.6.0 update 21 때문에 Eclipse 문제 발생  (0) 2010.08.09
Some Java Concurrency Tips  (0) 2010.06.11
Diagnosing Web Application OutOfMemoryErrors  (0) 2010.06.10
Understanding J2EE Class Loading  (0) 2010.06.03
Posted by '김용환'
,


조금 더 세련된 코딩을 주는 concurrent 팁을 공개한 자료..
대부분의 글은 Joshua Bloch가 쓴 ppt 자료임..

http://weblogs.java.net/blog/caroljmcdonald/archive/2009/09/17/some-java-concurrency-tips


Posted by '김용환'
,


Tomcat 7 개발 리더인 Mark Tomas가 발표한 자료.

http://www.infoq.com/presentations/Diagnosing-Memory-Leaks

Mark Tomas는 springsource에서 일하고 있음
http://www.springsource.com/people/mthomas

'java core' 카테고리의 다른 글

Random과 SecureRandom의 차이  (0) 2010.08.05
Some Java Concurrency Tips  (0) 2010.06.11
Understanding J2EE Class Loading  (0) 2010.06.03
클래스로딩에 대한 좋은 글  (0) 2010.06.03
로그를 통해서 ClassLoading 순서 보기  (0) 2010.06.03
Posted by '김용환'
,

http://blog.paran.com/dce/4799802

굉장히 좋은 글이라서 가져온다.



Java Class Loading Concepts

The following two basic principles will always apply:

o Each class retains an association with the class loader that loaded it. The getClassLoader() method of java.lang.Class returns the class loader that loaded the class, which cannot be changed after the class is loaded. This is the class loader that will be used if the class attempts to load classes by name.

o If the same class is loaded by two class loaders, classes loaded by the two class loaders will not be type compatible (although serialization will work).

The documentation of the java.lang.ClassLoader class further defines the following behavior for class loaders:

o Class loaders are hierarchical.
When a class loader is asked to load a class, it first asks its parent class loader to try to load the class. Only if the parent (and parent's ancestors) cannot load the class, will the original classloader attempt to load the class. The top of the class loader hierarchy is the bootstrap loader built into the JVM, which loads java.lang.Object().

o Although a class loader can see classes loaded by its parent(s), it cannot see classes loaded by its children.



Class Loading in J2EE

J2EE servers use multiple class loaders, largely because this allows dynamic application reloading. Clearly we don't want to reload all the application server's own classes on redeploying an application. This would mean that the application server would always need to be restarted. So application servers use different class loaders for application code to those they use for their own standard libraries, for example. Typically one or more new class loaders will be created for each application deployed on a server.

However, multiple class loaders are not usually used for different application-specific classes in the same application unless we use EJB (JSP pages may be given a separate class loader, but this doesn't usually affect application code).

In an EAR, the EJB class loader is often the parent of the WAR class loader. Orion and WebLogic, for example, both use this approach. This is a natural implementation approach, as WARs will typically access EJBs (and therefore need to be able to see at least EJB client classes), while EJBs do not access web components.

In this diagram the class loader hierarchy is represented by enclosing boxes. The parent-child relationship is represented by an enclosing box:

Assuming standard J2SE hierarchical class loading behavior, such a hierarchy will mean that any class can access classes in boxes that enclose its class loader. However, classes associated with the outer boxes cannot load classes in the inner boxes. Thus web application classes can see classes deployed in the application's EJBs and system classes. However, EJB classes cannot see web application classes, and classes installed at server-wide level cannot see any application-specific classes.


Class Loading in Integrated Enterprise Applications

Thus there are two basic problems relating to J2EE class loading, in the common case where EJB and web modules are included in the same enterprise application:

o Where do we hold the definitions of classes used in both EJBs and web applications?

o How do we ensure that two class loaders don't end up holding independent versions of the same class, resulting in class cast exceptions?


The Servlet 2.3 Specification's Class Loading Recommendations

The Servlet 2.3 specification (9.7.2) states that "It is recommended also that the application class loader be implemented so that classes and resources packaged within the WAR are loaded in preference to classes and resources residing in container-wide library JARs".

This clearly conflicts with the standard J2SE class loading behavior, as described in the Javadoc for the java.lang.ClassLoader class. As the WAR class loader must be a dynamic class loader, it must be the child of another class loader provided by the application server. Hence the Servlet 2.3 recommendation is the opposite of normal Java 2 class loading behavior, which clearly states that classes will be loaded from the child class loader (in this case the WAR class loader) only if they cannot be resolved by the ancestor class loaders.


The Java 1.3 Extension Mechanism Architecture in J2EE

Changes in J2SE 1.3 make it possible for JAR files to specify dependencies on other JAR files, by specifying a space-separated list of relative file paths in a Class-Path header in their /META-INF/MANIFEST.MF file.

Class-Path: Iog4j-1.2.jar 121-core.jar 121-ejbimpl.jar 121-jdbc.jar

This declares that the application-specific classes in the ticket-ejb.jar file depend on four infrastructure JARs, meaning that the EJBJAR file doesn't need to include any third party classes. These paths are relative. All these JAR files are included with the EJBJAR file in the root directly of the application EAR, as the following listing of the EAR's contents shows:

        META-INF/
        META-INF/MANIFEST.MF
        META-INF/application.xml
        121-core.jar
        i21-ejbimpl. jar
        121-jdbc.jar
        ticket-ejb.jar
        ticket.war
        Iog4j-1.2.jar

how to enable WAR manifest classpaths on Oracle 9iAS Release 2.

IBM documentation, WebSphere 4.0 supports manifest classpaths for WAR filesM

above links recommends using this when WARs and EJBs reference the same classes.

Orion and Oracle will also load manifest classpaths in EARs by default.

JBoss/Jetty does not appear to respect manifest classpaths in WARs
I haven't relied on this non-portable feature in packaging the sample application. The J2EE Reference Implementation also ignores manifest classpaths in WARs.

BEA discussing the use of manifest classpath


Thread Context Class Loader

getContextClassLoader() method on java.util.Thread.

o Class.forName (classname):
Will use the class loader of the helper class: in this case, the EJB class loader. This means that, if the EJB class loader is the parent of the WAR class loader, the helper will never be able to load classes in the WAR by name.

o Class.forName(classname, true, Thread.currentThread().getContextClassLoader()):
Will use the current container's class loader. This means that the helper will behave differently wherever it is running. If the EJB class loader is the parent of the WAR class loader, when the helper is used in the EJB container, it will only be able to load EJB classes and classes loaded by higher class loaders. If the helper is used in the WAR, it will be able to load WAR classes as well.



------------------------------------------------------------------------------------------


비슷한 예가 더 있다.

http://blog.naver.com/dipl19th?Redirect=Log&logNo=12448366



J2EE Classloading best practices

TheServerSide.com - TSS Featured Entry

자바 엔터프라이즈 어플리케이션에서 클래스로더의 작동 방식을 이해하는게 꽤나 중요하다. 기본적으로 Java2 platform에서는 클래스를 찾을때 현재 context의 클래스로더에서 먼저 찾는게 아니고 상위 context의 클래스로더에 클래스가 있는지 물어보고 없는 경우에 자기 자신의 context에 있는 클래스로더에서 클래스를 찾는게 원칙이다. 하지만 servlet spec에서는 웹 어플리케이션 context의 경우에만 클래스로더에서 먼저 찾고 없는 경우 상위 context에 물어보는게 예외적인 표준으로 되어있다.
이러한 원칙적인 배경을 알고 위의 링크를 읽어보면 웹어플리케이션을 구성하는데 큰 도움이 될 것 같다.

위의 링크를 대략 요약해보면....

Declare dependencies
Make dependencies explicit. Hidden or unknown dependencies will be left behind when you move your application to another environment. Specify the dependencies in the Manifest Class-Path entry of EJB-JAR or WAR file on the libraries packaged in the same application.

클래스들의 의존관계를 명확히 쓰라고 하는데 현재 웹 어플리케이션이 사용하는 클래스가 무엇인지 jar 또는 war의 manifest에 명시하라고 한다. 하지만 웹 어플리케이션에서 암묵적으로 WEB-INF/lib/*.jar, WEB-INF/classes를 자동으로 classpath로 본다는건 다 아는 사실인걸...


Group dependencies
Ensure that all dependencies are visible at the same level or above. If you must move a library, make sure all dependencies are still visible.

모든 클래스 의존 관계를 보이게(visible)하라.. 이 말의 의미는 위에서 java2 platform의 클래스로더 작동방식과 servlet spec에 정의된 웹어플리케이션의 클래스로더 작동방식을 안 다면 이해할 수 있는 부분이다. 어떤 클래스 A가 참조할 수 있는 클래스는 A와 같은 context에 있는 클래스 또는 상위 context의 클래스들이기 때문이다. Sibling context의 클래스는 볼 수 없다.

Minimize visibility
Dependency libraries should be placed at the lowest visibility level that satisfies all dependencies.

최소한의 사용할 클래스만 보이게 배치하라는 얘기인데, 특정 context에서 필요하지 않는 클래스들은 같은 context나 상위 context에 배치하는 걸 피하여 참조되는걸 피하라는 얘기다.


Share libraries
Avoid duplicating libraries. Duplication of libraries may make debugging classloading issues a nightmare. Share classes across a set of applications by using the configuration facilities provided by your application server. For example, use the tag in the global application.xml file in OC4J to share classes across all applications.

클래스들이 서로 다른 context에서 될 수 있으면 중복되지 않게 배치하고 공통으로 사용하는 것들은 한곳으로 모으라는 얘기이다. 이건 좀 주의해야하는데 웹 어플리케이션이 restart하여 해당 웹어플리케이션에서 사용하는 모든 클래스들이 reloading되는 상황에서도 이렇게 공통 영역으로 빠져있는 클래스들은 reloading이 되지 않는다.


Keep configurations portable
Choose configuration options in the following order:
o Standard J2EE options
o Options that can be expressed within your EAR file
o Server-level options
o J2SE extension options

이건 뭘까? 구체적으로 뭔지 번뜩 떠오르지 않는군..

=> @knight 주석, 이것은 클래스 로딩 순서를 의미한다..


Use the correct loader
If you call Class.forName(), always explicitly pass the loader returned by Thread.currentThread().getContextClassLoader. If you are loading a properties file, use Thread.currentThread().getContextClassLoader().getResourceAsStream().

설명 필요없음.


Avoid hardcoding of a specific parser in your application
Use JAXP API to access the underlying XML/XSL parsers in a vendor-neutral way instead of hard coding a specific XML parser in your application.

XML/XSL 파서를 사용할 때 J2SE 1.4의 표준 API를 이용하라는 얘기다. 부연 설명을 하자면 J2SE 1.4에서는 endorsed library라고 해서 JCP 이외의 기관에서 만들어진 표준 라이브러리에 대해서는 implementation을 교체할 수 있는 메커니즘을 제공하고 있다. Java runtime의 소스를 보면 XML/XSL 관련해서 apache에서 제공하는 crimson과 xalan을 사용하고 있는 것으로 보이는데 이걸 다른 걸로 교체할 수 있다. XML/XSL관련 라이브러리를 특정 디렉토리에 모아놓고 -Djava.endorsed.dirs 로 그 디렉토리를 지정해주면 된다.

Posted by '김용환'
,
Posted by '김용환'
,

자바를 이용해서 웹 서비스를 하든 어플리케이션을 하든, 보통 일반 개발자들이 어느 순서로 클래스 로딩이 되고 어떠한 작동을 하는지 알기 힘든 부분이 있다. 
로그만 추적하면, 클래스 로딩의 순서를 알게 되고 어떻게 진행되는지 도움이 많이 된다.


1. log4j 설정
debug로 print 한다. 
<logger name="com" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="general"/>
</logger>

<logger name="org" additivity="false">
<level value="DEBUG"/>
<appender-ref ref="general"/>
</logger>
<root>
<level value="DEBUG"/>
<appender-ref ref="STDOUT"/>
</root>




2. 클래스 로딩된 순서를 verbose하게 프린트한다

-verbose:class 
Display information about each class loaded. 


[Loaded com.TestExcelReader from file:/D:/source/web/WEB-INF/classes/]
[Loaded sun.misc.URLClassPath$JarLoader$1 from shared objects file]
[Loaded sun.misc.FileURLMapper from shared objects file]
[Loaded java.util.zip.ZipConstants from shared objects file]
[Loaded java.util.zip.ZipFile from shared objects file]
[Loaded java.util.jar.JarFile from shared objects file]
[Loaded sun.misc.JavaUtilJarAccess from shared objects file]
[Loaded java.util.jar.JavaUtilJarAccessImpl from shared objects file]
[Loaded sun.misc.JarIndex from shared objects file]
[Loaded sun.misc.ExtensionDependency from shared objects file]
[Loaded java.util.zip.ZipEntry from shared objects file]
[Loaded org.apache.poi.ss.usermodel.Workbook from file:/D:/source/web/WEB-INF/lib/poi-3.5-FINAL.jar]




3. -Djava.security.debug=all   
상황에 따라서는 java.security.debug를 출력하면 security manager 관련된 정보를 볼 필요도 있다.


scl: 
jar: beginEntry META-INF/MANIFEST.MF
jar: done with meta!
jar: nothing to verify!
scl:  getPermissions ProtectionDomain  (file:/D:/nhn/hangame_castest/web/WEB-INF/lib/poi-3.5-FINAL.jar <no signer certificates>)
 sun.misc.Launcher$AppClassLoader@19821f
 <no principals>
 java.security.Permissions@19ee1ac (
 (java.io.FilePermission \D:\nhn\hangame_castest\web\WEB-INF\lib\poi-3.5-FINAL.jar read)
 (java.lang.RuntimePermission exitVM)
)

Posted by '김용환'
,


                System.out.println(reader.getClass().getResource("."));
                System.out.println(reader.getClass().getClassLoader().getResource("."));

=> 테스트 결과

file:/D:/google_castest/web/WEB-INF/classes/com/google/cas/
file:/D:/google_castest/web/WEB-INF/classes/


Posted by '김용환'
,

sun.misc.GC 클래스

java core 2010. 5. 26. 14:40

sun.misc.GC 라는 클래스를 생전 처음 알게 되었다.

톰캣에서 sun.misc.GC를 이용하는 코드를 보게 되었다. 무엇인가 확인해본다.

최근에 톰캣 리더인 Mark Tomas 아저씨가 메모리릭 관련 리스너를 만든게 있다. 

JRE Memory Leak Prevention Listener (org.apache.catalina.core.JreMemoryLeakPreventionListener)

 http://tomcat.apache.org/tomcat-6.0-doc/config/listeners.html
gcDaemonProtection

Enables protection so that calls to sun.misc.GC.requestLatency(long) triggered by a web application do not result in a memory leak. Use of RMI is likely to trigger a call to this method. A side effect of enabling this protection is the creation of a thread named "GC Daemon". The protection is uses reflection to access internal Sun classes and may generate errors on startup on non-Sun JVMs. The default is true.


내용을 보면, Sun JVM 위에 돌아가는 GC Daemon를 하나 만들어 sun.misc.GC.requestLatency(long) 메소드를 날려주는 것이다. 쉽게 말해서 기존의 톰캣(자바)의 GC Daemon을 쓰지 않고 새로운 GC Daemon을 만드는 것이다.

http://www.docjar.com/docs/api/sun/misc/GC.html
public static LatencyRequest requestLatency(long latency) 
    Makes a new request for a garbage-collection latency of the given number of real-time milliseconds. A low-priority daemon thread makes a best effort to ensure that the maximum object-inspection age never exceeds the smallest of the currently active requests.


톰캣의 JreMemoryLeakPreventionListener.java 를 보면 의미를 더욱 더 명확히 할 수 있다.
톰캣 소스에서는 3600000 ms (즉, 3600초이며 60분의 latency를 주고 GC 하도록 메소드를 호출한다.

+            if (gcDaemonProtection) {
+                try {
+                    Class<?> clazz = Class.forName("sun.misc.GC");
+                    Method method = clazz.getDeclaredMethod("requestLatency",
+                            new Class[] {long.class});
+                    method.invoke(null, Long.valueOf(3600000));
+                } catch (ClassNotFoundException e) {
+                    if (System.getProperty("java.vendor").startsWith("Sun")) {
+                        log.error(sm.getString(
+                                "jreLeakListener.gcDaemonFail"), e);
+                    } else {
+                        log.debug(sm.getString(
+                                "jreLeakListener.gcDaemonFail"), e);
+                    }
+                }



내부적으로는 무슨 일을 하고 있을까? (하모니 소스는 이럴 때 보기 편하다..)


  167       /**  
168        * Represents an active garbage-collection latency request.  
Instances of  
169        * this class are created by the <code>{@link #requestLatency}</code> 
 170        * method.  Given a request, the only interesting operation is that of  
171        * cancellation.  172        */  
173       public static class LatencyRequest implements Comparable {  
174    
 175           /* Instance counter, used to generate unique identifers */  
176           private static long counter = 0;  
177     
178           /* Sorted set of active latency requests */  
179           private static SortedSet requests = null;  
180     
181           /* Examine the request set and reset the latency target if necessary.
  182            * Must be invoked while holding the lock.  
183            */  
184           private static void adjustLatencyIfNeeded() {  
185               if ((requests == null) || requests.isEmpty()) {  
186                   if (latencyTarget != NO_TARGET) {  
187                       setLatencyTarget(NO_TARGET);  
188                   }  
189               } else {  
190                   LatencyRequest r = (LatencyRequest)requests.first();  
191                   if (r.latency != latencyTarget) {  
192                       setLatencyTarget(r.latency);  
193                   } 
 194               }  
195           }  
196     
197           /* The requested latency, or NO_TARGET  
198            * if this request has been cancelled  
199            */  
200           private long latency;  
201     
202           /* Unique identifier for this request */  
203           private long id;  
204     
205           private LatencyRequest(long ms) {  
206               if (ms <= 0) { 
 207                   throw new IllegalArgumentException("Non-positive latency: "  
208                                                      + ms);  
209               }  
210               this.latency = ms;  
211               synchronized (lock) {  
212                   this.id = ++counter;  
213                   if (requests == null) {  
214                       requests = new TreeSet();  
215                   }  
216                   requests.add(this);  
217                   adjustLatencyIfNeeded();  
218               }  
219           }  
220     
221           /**  
222            * Cancels this latency request.  
223            *  
224            * @throws  IllegalStateException  
225            *          If this request has already been cancelled  
226            */  
227           public void cancel() {  
228               synchronized (lock) {  
229                   if (this.latency == NO_TARGET) { 
 230                       throw new IllegalStateException("Request already"  
231                                                       + " cancelled");  
232                   } 
 233                   if (!requests.remove(this)) {  
234                       throw new InternalError("Latency request "  
235                                               + this + " not found"); 
 236                   }  
237                   if (requests.isEmpty()) requests = null;  
238                   this.latency = NO_TARGET;  
239                   adjustLatencyIfNeeded();  
240               }  
241           } 
 242     
243           public int compareTo(Object o) { 
 244               LatencyRequest r = (LatencyRequest)o; 
 245               long d = this.latency - r.latency;  
246               if (d == 0) d = this.id - r.id;  
247               return (d < 0) ? -1 : ((d > 0) ? +1 : 0);  
248           }  
249     
250           public String toString() {  
251               return (LatencyRequest.class.getName()  
252                       + "[" + latency + "," + id + "]");  
253           } 
 254     
255       }  
256   

줄줄 따라가보니..Daemon을 생성하는 것이다. (Daemon있으면, notify 하면 되는 구조구요.)

Daemon은 Thread며, Daemon의 뜻에 맞게  low priority +1 를 두고 GC를 한다.
latency 시간의 값은 실제적으로는 expire되는 실제 wait값을 의미하는군..
   63       private static class LatencyLock extends Object { };   
64       private static Object lock = new LatencyLock();
private static class Daemon extends Thread {
   87      
88           public void run() {   
89               for (;;) {  
 90                   long l;   
91                   synchronized (lock) {   
92      
93                       l = latencyTarget;   
94                       if (l == NO_TARGET) {   
95                           /* No latency target, so exit */   
96                           GC.daemon = null;   
97                           return;   98                       }   
99     
100                       long d = maxObjectInspectionAge();  
101                       if (d >= l) {  
102                        /* Do a full collection.  There is a remote possibility
103                        * that a full collection will occurr between the time
 104                       * we sample the inspection age and the time the GC  
105                        * actually starts, but this is sufficiently unlikely  
106                         * that it doesn't seem worth the more expensive JVM 
 107                      * interface that would be required.  
108                            */  
109                           System.gc();  
110                           d = 0;  
111                       }  
112     
113                       /* Wait for the latency period to expire, 
 114                        * or for notification that the period has changed  
115                        */  
116                       try {  
117                           lock.wait(l - d);  
118                       } catch (InterruptedException x) {  
119                           continue;  
120                       }  
121                   }  
122               }  
123           }  
124     
125           private Daemon(ThreadGroup tg) {  
126               super(tg, "GC Daemon");  
127           }  
128    
 129           /* Create a new daemon thread in the root thread group */  
130           public static void create() { 
 131               PrivilegedAction pa = new PrivilegedAction() { 
 132                   public Object run() {  
133                       ThreadGroup tg = Thread.currentThread().getThreadGroup();  
134                       for (ThreadGroup tgn = tg; 
 135                            tgn != null;  
136                            tg = tgn, tgn = tg.getParent());  
137                       Daemon d = new Daemon(tg);  
138                       d.setDaemon(true);  
139                       d.setPriority(Thread.MIN_PRIORITY + 1); 
 140                       d.start();  
141                       GC.daemon = d;  
142                       return null;  
143                   }};  
144               AccessController.doPrivileged(pa);  
145           }  
146     
147       }


ObjectInspectAge가 무엇인가 API를 찾아봤더니. 다음과 같이 나왔다.
GC에 의해서 마지막으로 inspected된 heap object를 기준으로 얼마나 시간이 지났는지를 알려주는 최대값을 의미한다.. 내 생각에는 gc 하고 나서 얼마나 시간이 지났는지를 알려준다. 그 값을 염두하고 GC를 호출하는 저 Sense!!! 굿! 
    Returns the maximum object-inspection age, which is the number of real-time milliseconds that have elapsed since the least-recently-inspected heap object was last inspected by the garbage collector.


참고로 소스를 찾아보았다.. (apache harmony가 이럴 때 좋군.. 공부 대상 목표로 삼아두고..

Source : http://www.docjar.com/html/api/sun/misc/GC.java.html

다음의 결과는 무엇이 나올까.
System.out.println(sun.misc.GC.currentLatencyTarget());
System.out.println(sun.misc.GC.maxObjectInspectionAge());


0
1274847968291


 API 내용을 보면 좋을 것 같아서  올려놔 본다.
public static long currentLatencyTarget() 
    Returns the current smallest garbage-collection latency request, or zero if there are no active requests.

      Returns the maximum object-inspection age, which is the number of real-time milliseconds that have elapsed since the least-recently-inspected heap object was last inspected by the garbage collector.

      For simple stop-the-world collectors this value is just the time since the most recent collection. For generational collectors it is the time since the oldest generation was most recently collected. Other collectors are free to return a pessimistic estimate of the elapsed time, or simply the time since the last full collection was performed.

      Note that in the presence of reference objects, a given object that is no longer strongly reachable may have to be inspected multiple times before it can be reclaimed.


Posted by '김용환'
,