From aleksey.shipilev at oracle.com Wed Dec 3 21:26:06 2014 From: aleksey.shipilev at oracle.com (aleksey.shipilev at oracle.com) Date: Wed, 03 Dec 2014 21:26:06 +0000 Subject: hg: code-tools/jol: string-compress: add "savings(same)" to the report. Message-ID: <201412032126.sB3LQ6AQ003167@aojmv0008> Changeset: f4e9102f92fe Author: shade Date: 2014-12-04 00:25 +0300 URL: http://hg.openjdk.java.net/code-tools/jol/rev/f4e9102f92fe string-compress: add "savings(same)" to the report. ! jol-cli/src/main/java/org/openjdk/jol/MainStringCompress.java From aleksey.shipilev at oracle.com Wed Dec 3 21:30:57 2014 From: aleksey.shipilev at oracle.com (aleksey.shipilev at oracle.com) Date: Wed, 03 Dec 2014 21:30:57 +0000 Subject: hg: code-tools/jol: String compress: freeze the String layout of JDK 8. Message-ID: <201412032130.sB3LUvIU003958@aojmv0008> Changeset: 9a546334aa57 Author: shade Date: 2014-12-04 00:30 +0300 URL: http://hg.openjdk.java.net/code-tools/jol/rev/9a546334aa57 String compress: freeze the String layout of JDK 8. ! jol-cli/src/main/java/org/openjdk/jol/MainStringCompress.java From rafael.wth at gmail.com Mon Dec 15 13:03:51 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Mon, 15 Dec 2014 14:03:51 +0100 Subject: JOL object header information Message-ID: Hello everybody, first of all, thank you for this great tool, it helped me a lot to understand some cache line issues. Keep up the good work! After using JOL for looking into field layouts I became curious about HotSpot's mark word which is referred to in the examples on http://hg.openjdk.java.net/code-tools/jol/file/tip/jol-samples/src/main/java/org/openjdk/jol/samples/ Unfortunately, I stumbled when trying to interpret the mark word's contents of which I found a description in the commentary to this class: http://hg.openjdk.java.net/jdk6/jdk6/hotspot/file/8389681cd7b1/src/share/vm/oops/markOop.hpp To be certain, I wrote a minor extension to JOL which allows to print more detailed header information by something like: ClassLayout layout = ClassLayout.parseClass(Foo.class).withDetailedHeader(); where each header value is then mapped to its content in JOL's tabular overview instead of just printing "(object header)". My (minor) modification can found here: https://gist.github.com/raphw/7345bae62abd424fb040 However, it seems like the layout JOL retrieves diverges from the layout that is described in markOop.hpp - As one exemplary divergence, I found that the identity hash code seems to reach one bit further than the described 31 bit, e.g. when running ClassLayout layout = ClassLayout.parseClass(Object.class).withDetailedHeader(); Object foo = new Object(); System.out.println(Integer.toHexValue(foo.hashCode())); System.out.println(layout.toPrintable(foo)); the hex code often is one bit longer than the 31 bit that are specified in markOop.hpp - also, I cannot observe that the biased lock flag is set for the biased lock example. I understand that this mailing list is not a support forum for a potential beginner's problem when trying to learn more about HotSpot, I would still really appreciate an answer. Furthermore, I was wondering you would consider adding a similar feature for a detailed view of an instance's header to JOL. I am sure, others would benefit from the extended output when going through the examples that concern locking and hash code computation. Thank you for your time and best regards, Rafael From aleksey.shipilev at oracle.com Mon Dec 15 14:10:38 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Mon, 15 Dec 2014 17:10:38 +0300 Subject: JOL object header information In-Reply-To: References: Message-ID: <548EEBDE.7030701@oracle.com> Hi Rafael, On 15.12.2014 16:03, Rafael Winterhalter wrote: > To be certain, I wrote a minor extension to JOL which allows to print more > detailed header information by something like: > > ClassLayout layout = ClassLayout.parseClass(Foo.class).withDetailedHeader(); > > where each header value is then mapped to its content in JOL's tabular > overview instead of just printing "(object header)". My (minor) > modification can found here: > https://gist.github.com/raphw/7345bae62abd424fb040 Thanks! Not sure it belongs in JOL codebase though, see below: > However, it seems like the layout JOL retrieves diverges from the layout > that is described in markOop.hpp - As one exemplary divergence, I found > that the identity hash code seems to reach one bit further than the > described 31 bit, e.g. when running JOL deliberately back away from trying to parse the object metadata, because that would diverge from the current VM layout without warning. It is scary to replicate something written out in the HotSpot comments into the otherwise VM oblivious tools. I still think the right way to do this is to involve the Serviceability Agent that ships with each VM version, and follows/queries the VM internals: http://mail.openjdk.java.net/pipermail/jol-dev/2014-September/000016.html I admit, using the SA is PITA. For one, you can not attach to yourself, and therefore you need to fork out the VM to get this kind of data. Still, this is doable, and is more maintainable than trying to keep the JOL code in sync. That also highlights the route to follow-up with hashcode sizes and such: SA is the source of truth, not the HotSpot comments. Thanks, -Aleksey. From serkanozal86 at hotmail.com Mon Dec 15 14:17:26 2014 From: serkanozal86 at hotmail.com (=?windows-1254?B?c2Vya2FuIPZ6YWw=?=) Date: Mon, 15 Dec 2014 16:17:26 +0200 Subject: JOL object header information In-Reply-To: <548EEBDE.7030701@oracle.com> References: , <548EEBDE.7030701@oracle.com> Message-ID: Hi Aleksey, As you said SA is specific to its shipped JVM version.So I create a composite "sa-jdi.jar" that containts all sa-jdi jar files fro Java 6, 7 and 8 in different sub directories. Then I use them with a JVM version aware custom classloader as here: https://github.com/serkan-ozal/jillegal/blob/master/src/main/java/tr/com/serkanozal/jillegal/util/compressedoops/hotspot/HotspotJvmAwareSaJdiClassLoader.java https://github.com/serkan-ozal/jillegal/blob/master/src/main/java/tr/com/serkanozal/jillegal/util/compressedoops/hotspot/HotspotServiceabilityAgentBasedCompressedOopsInfoProvider.java Currently, it handles only major versions of JDK distribution, not minors. WDYT about this solution/workaround ? I didn't send a patch for this stuff to JOL, since I am still not sure about is this approach is right or not ? Regards. -- Serkan ?ZAL > Date: Mon, 15 Dec 2014 17:10:38 +0300 > From: aleksey.shipilev at oracle.com > To: jol-dev at openjdk.java.net > Subject: Re: JOL object header information > > Hi Rafael, > > On 15.12.2014 16:03, Rafael Winterhalter wrote: > > To be certain, I wrote a minor extension to JOL which allows to print more > > detailed header information by something like: > > > > ClassLayout layout = ClassLayout.parseClass(Foo.class).withDetailedHeader(); > > > > where each header value is then mapped to its content in JOL's tabular > > overview instead of just printing "(object header)". My (minor) > > modification can found here: > > https://gist.github.com/raphw/7345bae62abd424fb040 > > Thanks! Not sure it belongs in JOL codebase though, see below: > > > However, it seems like the layout JOL retrieves diverges from the layout > > that is described in markOop.hpp - As one exemplary divergence, I found > > that the identity hash code seems to reach one bit further than the > > described 31 bit, e.g. when running > > JOL deliberately back away from trying to parse the object metadata, > because that would diverge from the current VM layout without warning. > It is scary to replicate something written out in the HotSpot comments > into the otherwise VM oblivious tools. > > I still think the right way to do this is to involve the Serviceability > Agent that ships with each VM version, and follows/queries the VM > internals: > http://mail.openjdk.java.net/pipermail/jol-dev/2014-September/000016.html > > I admit, using the SA is PITA. For one, you can not attach to yourself, > and therefore you need to fork out the VM to get this kind of data. > Still, this is doable, and is more maintainable than trying to keep the > JOL code in sync. > > That also highlights the route to follow-up with hashcode sizes and > such: SA is the source of truth, not the HotSpot comments. > > Thanks, > -Aleksey. > > From aleksey.shipilev at oracle.com Mon Dec 15 14:28:41 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Mon, 15 Dec 2014 17:28:41 +0300 Subject: JOL object header information In-Reply-To: References: , <548EEBDE.7030701@oracle.com> Message-ID: <548EF019.9060200@oracle.com> Hi Serkan, On 15.12.2014 17:17, serkan ?zal wrote: > As you said SA is specific to its shipped JVM version. > So I create a composite "sa-jdi.jar" that containts all sa-jdi jar files > fro Java 6, 7 and 8 in different sub directories. Then I use them with a > JVM version aware custom classloader as here: IDK what license those files are, and therefore I haven't looked there, but I dig what you do. > WDYT about this solution/workaround ? I think that's the right route for at least compressed oops stuff. Parsing object header would probably require running the actual SA code, because the changing object header format will probably require modified parsing code. > I didn't send a patch for this stuff to JOL, since I am still not sure > about is this approach is right or not ? I do think that we need to ask the user to provide us with the concrete sa-jdi.jar, load it, and either pull the constants from there, or even run the SA code from there. We may even look around in $JAVA_HOME for sa-jdi.jar. Shipping sa-jdi.jar for "major" versions defies the purpose of having SA to begin with: provide the interface to *current* VM, knowing SA is synced up with all the mundane details of current VM code. It is wishful thinking (and a maintenance nightmare) to presume the internal layout would change only in major versions. Thanks, -Aleksey. From serkanozal86 at hotmail.com Mon Dec 15 15:02:10 2014 From: serkanozal86 at hotmail.com (=?windows-1254?B?c2Vya2FuIPZ6YWw=?=) Date: Mon, 15 Dec 2014 17:02:10 +0200 Subject: JOL object header information In-Reply-To: <548EF019.9060200@oracle.com> References: , <548EEBDE.7030701@oracle.com> , <548EF019.9060200@oracle.com> Message-ID: Hi Aleksey, So +1 from my side for 1. Try to find SA jar in the classpath. (User may provide the sa-jdi.jar) 1.1. If couldn't be found, look at $JAVA_HOME/lib/sa-jdi.jar (as you offered) 1.1.1. If SA jar is available at there, use it 1.1.2. Throw exception, or display a warning message that some features of JOL is not supported because of non-existing SA library. Or use compisite sa-jdi.jar via JVM version aware classloader by printing a log message about because of minor version changes, somethings may be broken. 1.2. Use SA from classpath.2. Create a new process to attach current process with SA. (If current processes attaches itself as Instrumentation agent, current process hangs forever, because when SA agent is attached to a JVM process, JVM suspends attached process)3. Get data from current process with newly created process.4. Return result to current process (caller process) via pipe between processes (Input/Output Stream) WDYT ? Regards. > Date: Mon, 15 Dec 2014 17:28:41 +0300 > From: aleksey.shipilev at oracle.com > To: serkanozal86 at hotmail.com; jol-dev at openjdk.java.net > Subject: Re: JOL object header information > > Hi Serkan, > > On 15.12.2014 17:17, serkan ?zal wrote: > > As you said SA is specific to its shipped JVM version. > > So I create a composite "sa-jdi.jar" that containts all sa-jdi jar files > > fro Java 6, 7 and 8 in different sub directories. Then I use them with a > > JVM version aware custom classloader as here: > > IDK what license those files are, and therefore I haven't looked there, > but I dig what you do. > > > WDYT about this solution/workaround ? > > I think that's the right route for at least compressed oops stuff. > > Parsing object header would probably require running the actual SA code, > because the changing object header format will probably require modified > parsing code. > > > I didn't send a patch for this stuff to JOL, since I am still not sure > > about is this approach is right or not ? > > I do think that we need to ask the user to provide us with the concrete > sa-jdi.jar, load it, and either pull the constants from there, or even > run the SA code from there. We may even look around in $JAVA_HOME for > sa-jdi.jar. > > Shipping sa-jdi.jar for "major" versions defies the purpose of having SA > to begin with: provide the interface to *current* VM, knowing SA is > synced up with all the mundane details of current VM code. It is wishful > thinking (and a maintenance nightmare) to presume the internal layout > would change only in major versions. > > Thanks, > -Aleksey. > From serkanozal86 at hotmail.com Mon Dec 15 15:24:05 2014 From: serkanozal86 at hotmail.com (=?iso-8859-1?Q?Serkan_=D6ZAL?=) Date: Mon, 15 Dec 2014 17:24:05 +0200 Subject: JOL object header information In-Reply-To: References: , <548EEBDE.7030701@oracle.com> , <548EF019.9060200@oracle.com> Message-ID: Hi all, Sorry for bad indentation at my previous mail. Hi Aleksey, So +1 from my side for 1. Try to find SA jar in the classpath. (User may provide the sa-jdi.jar) 1.1. If couldn't be found, look at $JAVA_HOME/lib/sa-jdi.jar (as you offered) 1.1.1. If SA jar is available at there, use it 1.1.2. Throw exception, or display a warning message that some features of JOL is not supported because of non-existing SA library. Or use compisite sa-jdi.jar via JVM version aware classloader by printing a log message about because of minor version changes, somethings may be broken. 1.2. Use SA from class path. 2. Create a new process to attach current process with SA. (If current processes attaches itself as Instrumentation agent, current process hangs forever, because when SA agent is attached to a JVM process, JVM suspends attached process) 3. Get data from current process with newly created process. 4. Return result to current process (caller process) via pipe between processes (Input/Output Stream) WDYT ? Regards. ? Serkan ?ZAL On 15 Dec 2014, at 17:02, serkan ?zal wrote: > Hi Aleksey, > So +1 from my side for > 1. Try to find SA jar in the classpath. (User may provide the sa-jdi.jar) 1.1. If couldn't be found, look at $JAVA_HOME/lib/sa-jdi.jar (as you offered) 1.1.1. If SA jar is available at there, use it 1.1.2. Throw exception, or display a warning message that some features of JOL is not supported because of non-existing SA library. Or use compisite sa-jdi.jar via JVM version aware classloader by printing a log message about because of minor version changes, somethings may be broken. 1.2. Use SA from classpath.2. Create a new process to attach current process with SA. (If current processes attaches itself as Instrumentation agent, current process hangs forever, because when SA agent is attached to a JVM process, JVM suspends attached process)3. Get data from current process with newly created process.4. Return result to current process (caller process) via pipe between processes (Input/Output Stream) > WDYT ? > Regards. > >> Date: Mon, 15 Dec 2014 17:28:41 +0300 >> From: aleksey.shipilev at oracle.com >> To: serkanozal86 at hotmail.com; jol-dev at openjdk.java.net >> Subject: Re: JOL object header information >> >> Hi Serkan, >> >> On 15.12.2014 17:17, serkan ?zal wrote: >>> As you said SA is specific to its shipped JVM version. >>> So I create a composite "sa-jdi.jar" that containts all sa-jdi jar files >>> fro Java 6, 7 and 8 in different sub directories. Then I use them with a >>> JVM version aware custom classloader as here: >> >> IDK what license those files are, and therefore I haven't looked there, >> but I dig what you do. >> >>> WDYT about this solution/workaround ? >> >> I think that's the right route for at least compressed oops stuff. >> >> Parsing object header would probably require running the actual SA code, >> because the changing object header format will probably require modified >> parsing code. >> >>> I didn't send a patch for this stuff to JOL, since I am still not sure >>> about is this approach is right or not ? >> >> I do think that we need to ask the user to provide us with the concrete >> sa-jdi.jar, load it, and either pull the constants from there, or even >> run the SA code from there. We may even look around in $JAVA_HOME for >> sa-jdi.jar. >> >> Shipping sa-jdi.jar for "major" versions defies the purpose of having SA >> to begin with: provide the interface to *current* VM, knowing SA is >> synced up with all the mundane details of current VM code. It is wishful >> thinking (and a maintenance nightmare) to presume the internal layout >> would change only in major versions. >> >> Thanks, >> -Aleksey. >> > From aleksey.shipilev at oracle.com Mon Dec 15 15:27:51 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Mon, 15 Dec 2014 18:27:51 +0300 Subject: JOL object header information In-Reply-To: References: , <548EEBDE.7030701@oracle.com> , <548EF019.9060200@oracle.com> Message-ID: <548EFDF7.9010400@oracle.com> On 15.12.2014 18:02, serkan ?zal wrote: > 1. Try to find SA jar in the classpath. (User may provide the sa-jdi.jar) > 1.1. If couldn't be found, look at $JAVA_HOME/lib/sa-jdi.jar (as you > offered) > 1.1.1. If SA jar is available at there, use it > 1.1.2. Throw exception, or display a warning message that some > features of JOL is not supported because of non-existing SA library. Or > use compisite sa-jdi.jar via JVM version aware classloader by printing a > log message about because of minor version changes, somethings may be > broken. Print warning, and gracefully degrade. > 1.2. Use SA from classpath. > 2. Create a new process to attach current process with SA. (If current > processes attaches itself as Instrumentation agent, current process > hangs forever, because when SA agent is attached to a JVM process, JVM > suspends attached process) > 3. Get data from current process with newly created process. > 4. Return result to current process (caller process) via pipe between > processes (Input/Output Stream) > > WDYT ? Yes, that would be perfect. -Aleksey. From aleksey.shipilev at oracle.com Tue Dec 16 08:06:36 2014 From: aleksey.shipilev at oracle.com (aleksey.shipilev at oracle.com) Date: Tue, 16 Dec 2014 08:06:36 +0000 Subject: hg: code-tools/jol: 7901131: jol-estimates mistreat char[] as the ordinary class, not the array Message-ID: <201412160806.sBG86bg3024741@aojmv0008> Changeset: 8f820e6eb250 Author: shade Date: 2014-12-16 11:05 +0300 URL: http://hg.openjdk.java.net/code-tools/jol/rev/8f820e6eb250 7901131: jol-estimates mistreat char[] as the ordinary class, not the array ! jol-core/src/main/java/org/openjdk/jol/info/ClassData.java From rafael.wth at gmail.com Tue Dec 16 10:43:09 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Tue, 16 Dec 2014 11:43:09 +0100 Subject: JOL object header information Message-ID: First of all, thanks for the hint to the ServiceabiltyAgent, did not even know HotSpot had this. If this is considered feasible: One could play similar tricks and self-attach an agent via tools.jar and always print the correct instance size via the Instrumentation API and only print the estimated size if this is impossible? I would be more than happy to implement the feature, I just did something similar for a test suite that required an agent. Most people run JOL on an OpenJDK VM anyways? The only concern is that this would break with Jigsaw but this is also true for the proposal to integrating the ServiceabiltyAgent. Regards, Rafael From aleksey.shipilev at oracle.com Wed Dec 17 09:24:38 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Wed, 17 Dec 2014 12:24:38 +0300 Subject: JOL object header information In-Reply-To: References: Message-ID: <54914BD6.8050108@oracle.com> On 12/16/2014 01:43 PM, Rafael Winterhalter wrote: > If this is considered feasible: One could play similar tricks and > self-attach an agent via tools.jar and always print the correct instance > size via the Instrumentation API and only print the estimated size if this > is impossible? I would be more than happy to implement the feature, I just > did something similar for a test suite that required an agent. Well, JOL can already be manually attached to as an agent, and it will use Instrumentation API then, see the "Instance size" below. It would be interesting to experiment with self-attachment though. $ java -jar jol-internals.jar java.lang.String Running 64-bit HotSpot VM. Using compressed references with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] java.lang.String object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) N/A 4 4 (object header) N/A 8 4 (object header) N/A 12 4 char[] String.value N/A 16 4 int String.hash N/A 20 4 (loss due to the next object alignment) Instance size: 24 bytes (estimated, add this JAR via -javaagent: to get accurate result) Space losses: 0 bytes internal + 4 bytes external = 4 bytes total $ java -javaagent:jol-internals.jar -jar jol-internals.jar java.lang.String Running 64-bit HotSpot VM. Using compressed references with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] java.lang.String object internals: OFFSET SIZE TYPE DESCRIPTION VALUE 0 4 (object header) N/A 4 4 (object header) N/A 8 4 (object header) N/A 12 4 char[] String.value N/A 16 4 int String.hash N/A 20 4 (loss due to the next object alignment) Instance size: 24 bytes (reported by VM agent) Space losses: 0 bytes internal + 4 bytes external = 4 bytes total -Aleksey. From serkanozal86 at hotmail.com Wed Dec 17 10:25:55 2014 From: serkanozal86 at hotmail.com (=?UTF-8?B?U2Vya2FuIMOWWkFM?=) Date: Wed, 17 Dec 2014 12:25:55 +0200 Subject: JOL object header information In-Reply-To: <54914BD6.8050108@oracle.com> References: <54914BD6.8050108@oracle.com> Message-ID: Aleksey Shipilev yazm??: > On 12/16/2014 01:43 PM, Rafael Winterhalter wrote: > >> If this is considered feasible: One could play similar tricks and >> self-attach an agent via tools.jar and always print the correct instance >> size via the Instrumentation API and only print the estimated size if this >> is impossible? I would be more than happy to implement the feature, I just >> did something similar for a test suite that required an agent. >> > > Well, JOL can already be manually attached to as an agent, and it will > use Instrumentation API then, see the "Instance size" below. It would be > interesting to experiment with self-attachment though. > > $ java -jar jol-internals.jar java.lang.String > Running 64-bit HotSpot VM. > Using compressed references with 3-bit shift. > Objects are 8 bytes aligned. > Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] > Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] > > java.lang.String object internals: > OFFSET SIZE TYPE DESCRIPTION VALUE > 0 4 (object header) N/A > 4 4 (object header) N/A > 8 4 (object header) N/A > 12 4 char[] String.value N/A > 16 4 int String.hash N/A > 20 4 (loss due to the next object alignment) > Instance size: 24 bytes (estimated, add this JAR via -javaagent: to get > accurate result) > Space losses: 0 bytes internal + 4 bytes external = 4 bytes total > > > $ java -javaagent:jol-internals.jar -jar jol-internals.jar java.lang.String > Running 64-bit HotSpot VM. > Using compressed references with 3-bit shift. > Objects are 8 bytes aligned. > Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] > Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] > > java.lang.String object internals: > OFFSET SIZE TYPE DESCRIPTION VALUE > 0 4 (object header) N/A > 4 4 (object header) N/A > 8 4 (object header) N/A > 12 4 char[] String.value N/A > 16 4 int String.hash N/A > 20 4 (loss due to the next object alignment) > Instance size: 24 bytes (reported by VM agent) > Space losses: 0 bytes internal + 4 bytes external = 4 bytes total > > > -Aleksey. > > > > > Hi Aleksey, If you want to use self attached Instrumentation agent, I can send a patch similar like I did here: https://github.com/serkan-ozal/jillegal-agent/blob/master/src/main/java/tr/com/serkanozal/jillegal/agent/JillegalAgent.java#L174 BTW, I will also send another patch for Hotspot Servicability Agent support (not just for compressed-oops, for general use of it, compressed-oops will be only a feature of SA support patch) possibly in 2 weeks. Sorry for latency :) Regards. -- Serkan ?ZAL From rafael.wth at gmail.com Wed Dec 17 13:56:04 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Wed, 17 Dec 2014 14:56:04 +0100 Subject: JOL object header information Message-ID: Well, obviously, I can do better than Serkan ;) Self-attachment, for your consideration: https://gist.github.com/raphw/05785c61b2b3dd263224 From serkanozal86 at hotmail.com Wed Dec 17 14:16:05 2014 From: serkanozal86 at hotmail.com (=?iso-8859-1?Q?Serkan_=D6ZAL?=) Date: Wed, 17 Dec 2014 16:16:05 +0200 Subject: JOL object header information In-Reply-To: References: Message-ID: Nice hack Rafael +1 But I think, instead of creating agent jar file on the fly, it maybe better that JOL jar itself can be an instrumentation agent jar by just adding a few lines its MANIFEST file. On 17 Dec 2014, at 15:56, Rafael Winterhalter wrote: > Well, obviously, I can do better than Serkan ;) > Self-attachment, for your consideration: > https://gist.github.com/raphw/05785c61b2b3dd263224 > From rafael.wth at gmail.com Wed Dec 17 14:41:13 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Wed, 17 Dec 2014 15:41:13 +0100 Subject: JOL object header information In-Reply-To: References: Message-ID: I agree to 99%. But this other approach only works if VMSupport was loaded by the system ClassLoader where agents must be loaded from. Otherwise, the VMSupport that is the agent and the VMSupport that installs the agent are two different classes and the set INSTRUMENTATION field would belong to a different class. This is why I prefer the hack by adding an additional installer class that is minimal in byte size and does not carry any other class dependencies and inject this class. Also, I only access it by reflection in order to avoid these class identity issues. Might not be as relevant for JOL as I guess most people do not really use this from a servlet container or somewhere but I guess there might be corner cases (?). 2014-12-17 15:16 GMT+01:00 Serkan ?ZAL : > > Nice hack Rafael +1 > > But I think, instead of creating agent jar file on the fly, it maybe > better that JOL jar itself can be an instrumentation agent jar by just > adding a few lines its MANIFEST file. > > On 17 Dec 2014, at 15:56, Rafael Winterhalter > wrote: > > > Well, obviously, I can do better than Serkan ;) > > Self-attachment, for your consideration: > > https://gist.github.com/raphw/05785c61b2b3dd263224 > > > > From aleksey.shipilev at oracle.com Thu Dec 18 19:01:52 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Thu, 18 Dec 2014 22:01:52 +0300 Subject: JOL object header information In-Reply-To: References: <54914BD6.8050108@oracle.com> Message-ID: <549324A0.2080500@oracle.com> On 12/17/2014 01:25 PM, Serkan ?ZAL wrote: > BTW, I will also send another patch for Hotspot Servicability Agent > support (not just for compressed-oops, for general use of it, > compressed-oops will be only a feature of SA support patch) possibly in > 2 weeks. Sorry for latency :) Sure, please go ahead. We have plenty of time over the New Year holidays. Thanks, -Aleksey. From aleksey.shipilev at oracle.com Thu Dec 18 20:02:22 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Thu, 18 Dec 2014 23:02:22 +0300 Subject: JOL object header information In-Reply-To: References: Message-ID: <549332CE.8030504@oracle.com> Hi Rafael, Serkan, On 12/17/2014 05:41 PM, Rafael Winterhalter wrote: > But this other approach only works if VMSupport was loaded by the system > ClassLoader where agents must be loaded from. Otherwise, the VMSupport that > is the agent and the VMSupport that installs the agent are two different > classes and the set INSTRUMENTATION field would belong to a different > class. This is why I prefer the hack by adding an additional installer > class that is minimal in byte size and does not carry any other class > dependencies and inject this class. Also, I only access it by reflection in > order to avoid these class identity issues. Might not be as relevant for > JOL as I guess most people do not really use this from a servlet container > or somewhere but I guess there might be corner cases (?). You will be suprised *where* people use JOL. Therefore, I would not like to artificially limit the its applicability. I like Rafael's approach. Rafael, can you send the patch either in attachment or inline on this list? OpenJDK ToU requires us to accept the incoming changes on openjdk.java.net. You seem to already have the OCA signed, so we are in clear about attribution. Thanks, -Aleksey. From rafael.wth at gmail.com Thu Dec 18 22:04:07 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Thu, 18 Dec 2014 23:04:07 +0100 Subject: JOL object header information In-Reply-To: <549332CE.8030504@oracle.com> References: <549332CE.8030504@oracle.com> Message-ID: Hi all, sure thing. Find the patch attached. I signed the OCA a year ago when I patched something for glassfish. If this is valid for JOL, great, otherwise ping me. Index: jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java (revision 31:9a546334aa57fa0e114db159b2a8a5345c249b3e) +++ jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java (revision 31+:9a546334aa57+) @@ -35,13 +35,22 @@ import javax.management.openmbean.CompositeDataSupport; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.InputStream; +import java.io.File; +import java.io.FileOutputStream; import java.lang.instrument.Instrumentation; import java.lang.management.ManagementFactory; import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLClassLoader; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Random; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -55,6 +64,8 @@ private static Instrumentation INSTRUMENTATION; + private static boolean installAttempt; + public static final Unsafe U; public static final String VM_NAME; @@ -253,6 +264,7 @@ private final boolean exactSizeAvail; public SizeInfo(Object o, ClassLayout layout) { + VMSupport.installInstrumentation(); exactSizeAvail = VMSupport.INSTRUMENTATION != null && o != null; size = exactSizeAvail ? (int) VMSupport.INSTRUMENTATION.getObjectSize(o) : layout.instanceSize(); } @@ -418,6 +430,7 @@ } public static int sizeOf(Object o) { + installInstrumentation(); if (VMSupport.INSTRUMENTATION != null) { return VMSupport.align((int) VMSupport.INSTRUMENTATION.getObjectSize(o)); } @@ -425,6 +438,79 @@ return new CurrentLayouter().layout(ClassData.parseInstance(o)).instanceSize(); } + private static void installInstrumentation() { + if (!installAttempt) { + try { + doInstall(); + } catch (Exception ignored) { + } + } + } + + private static synchronized void doInstall() throws Exception { + if (installAttempt) { + return; + } + installAttempt = true; + ClassLoader classLoader = new URLClassLoader(new URL[]{new File(System.getProperty("java.home") + .replace('\\', '/') + "/../lib/tools.jar").toURI().toURL()}, null); + Class virtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine"); + String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); + Object virtualMachineInstance = virtualMachine.getDeclaredMethod("attach", String.class) + .invoke(null, runtimeName.substring(0, runtimeName.indexOf('@'))); + try { + File agentFile = File.createTempFile("jolAgent", ".jar"); + try { + saveAgentJar(agentFile); + virtualMachine.getDeclaredMethod("loadAgent", String.class, String.class) + .invoke(virtualMachineInstance, agentFile.getAbsolutePath(), ""); + INSTRUMENTATION = doGetInstrumentation(); + } finally { + agentFile.delete(); + } + } finally { + virtualMachine.getDeclaredMethod("detach").invoke(virtualMachineInstance); + } + } + + private static Instrumentation doGetInstrumentation() { + try { + Field field = ClassLoader.getSystemClassLoader() + .loadClass(Installer.class.getName()) + .getDeclaredField("instrumentation"); + field.setAccessible(true); + return (Instrumentation) field.get(null); + } catch (Exception e) { + throw null; + } + } + + private static void saveAgentJar(File agentFile) throws Exception { + InputStream inputStream = Installer.class.getResourceAsStream('/' + Installer.class.getName().replace('.', '/') + ".class"); + if (inputStream == null) { + return; + } + try { + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), Installer.class.getName()); + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(agentFile), manifest); + try { + jarOutputStream.putNextEntry(new JarEntry('/' + Installer.class.getName().replace('.', '/') + ".class")); + byte[] buffer = new byte[1024]; + int index; + while ((index = inputStream.read(buffer)) != -1) { + jarOutputStream.write(buffer, 0, index); + } + jarOutputStream.closeEntry(); + } finally { + jarOutputStream.close(); + } + } finally { + inputStream.close(); + } + } + /** * Produces the toString string, only calling toString() on known types, * which do not mutate the instance. @@ -526,6 +612,15 @@ static class MyDoubles4 { private double f1, f2, f3, f4; + } + + public static class Installer { + + private static volatile Instrumentation instrumentation; + + public static void agentmain(String agentArgs, Instrumentation inst) { + instrumentation = inst; + } } } 2014-12-18 21:02 GMT+01:00 Aleksey Shipilev : > > Hi Rafael, Serkan, > > On 12/17/2014 05:41 PM, Rafael Winterhalter wrote: > > But this other approach only works if VMSupport was loaded by the system > > ClassLoader where agents must be loaded from. Otherwise, the VMSupport > that > > is the agent and the VMSupport that installs the agent are two different > > classes and the set INSTRUMENTATION field would belong to a different > > class. This is why I prefer the hack by adding an additional installer > > class that is minimal in byte size and does not carry any other class > > dependencies and inject this class. Also, I only access it by reflection > in > > order to avoid these class identity issues. Might not be as relevant for > > JOL as I guess most people do not really use this from a servlet > container > > or somewhere but I guess there might be corner cases (?). > > You will be suprised *where* people use JOL. Therefore, I would not like > to artificially limit the its applicability. > > I like Rafael's approach. Rafael, can you send the patch either in > attachment or inline on this list? OpenJDK ToU requires us to accept the > incoming changes on openjdk.java.net. You seem to already have the OCA > signed, so we are in clear about attribution. > > Thanks, > -Aleksey. > > > From aleksey.shipilev at oracle.com Thu Dec 18 22:48:02 2014 From: aleksey.shipilev at oracle.com (aleksey.shipilev at oracle.com) Date: Thu, 18 Dec 2014 22:48:02 +0000 Subject: hg: code-tools/jol: 7901220: Use dynamic agent self-attachment to get Instrumentation API in JOL Message-ID: <201412182248.sBIMm2dt027119@aojmv0008> Changeset: be8776814beb Author: shade Date: 2014-12-19 01:45 +0300 URL: http://hg.openjdk.java.net/code-tools/jol/rev/be8776814beb 7901220: Use dynamic agent self-attachment to get Instrumentation API in JOL Contributed-by: Rafael Winterhalter ! jol-cli/pom.xml ! jol-core/src/main/java/org/openjdk/jol/info/ClassLayout.java + jol-core/src/main/java/org/openjdk/jol/util/InstrumentationSupport.java ! jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java ! jol-samples/pom.xml From aleksey.shipilev at oracle.com Thu Dec 18 22:48:57 2014 From: aleksey.shipilev at oracle.com (Aleksey Shipilev) Date: Fri, 19 Dec 2014 01:48:57 +0300 Subject: JOL object header information In-Reply-To: References: <549332CE.8030504@oracle.com> Message-ID: <549359D9.7030702@oracle.com> Thank you, I have refactored this a bit, and committed: https://bugs.openjdk.java.net/browse/CODETOOLS-7901220 http://hg.openjdk.java.net/code-tools/jol/rev/be8776814beb -Aleksey. On 12/19/2014 01:04 AM, Rafael Winterhalter wrote: > Hi all, sure thing. Find the patch attached. I signed the OCA a year ago > when I patched something for glassfish. If this is valid for JOL, great, > otherwise ping me. > > Index: jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java > IDEA additional info: > Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP > <+>UTF-8 > =================================================================== > --- jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java (revision 31:9a546334aa57fa0e114db159b2a8a5345c249b3e) > +++ jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java (revision 31+:9a546334aa57+) > @@ -35,13 +35,22 @@ > import javax.management.openmbean.CompositeDataSupport; > import java.io.PrintWriter; > import java.io.StringWriter; > +import java.io.InputStream; > +import java.io.File; > +import java.io.FileOutputStream; > import java.lang.instrument.Instrumentation; > import java.lang.management.ManagementFactory; > import java.lang.reflect.Field; > +import java.net.URL; > +import java.net.URLClassLoader; > import java.security.AccessController; > import java.security.PrivilegedAction; > import java.util.Arrays; > import java.util.Random; > +import java.util.jar.Attributes; > +import java.util.jar.JarEntry; > +import java.util.jar.JarOutputStream; > +import java.util.jar.Manifest; > import java.util.regex.Matcher; > import java.util.regex.Pattern; > > @@ -55,6 +64,8 @@ > > private static Instrumentation INSTRUMENTATION; > > + private static boolean installAttempt; > + > public static final Unsafe U; > > public static final String VM_NAME; > @@ -253,6 +264,7 @@ > private final boolean exactSizeAvail; > > public SizeInfo(Object o, ClassLayout layout) { > + VMSupport.installInstrumentation(); > exactSizeAvail = VMSupport.INSTRUMENTATION != null && o != null; > size = exactSizeAvail ? (int) VMSupport.INSTRUMENTATION.getObjectSize(o) : layout.instanceSize(); > } > @@ -418,6 +430,7 @@ > } > > public static int sizeOf(Object o) { > + installInstrumentation(); > if (VMSupport.INSTRUMENTATION != null) { > return VMSupport.align((int) VMSupport.INSTRUMENTATION.getObjectSize(o)); > } > @@ -425,6 +438,79 @@ > return new CurrentLayouter().layout(ClassData.parseInstance(o)).instanceSize(); > } > > + private static void installInstrumentation() { > + if (!installAttempt) { > + try { > + doInstall(); > + } catch (Exception ignored) { > + } > + } > + } > + > + private static synchronized void doInstall() throws Exception { > + if (installAttempt) { > + return; > + } > + installAttempt = true; > + ClassLoader classLoader = new URLClassLoader(new URL[]{new File(System.getProperty("java.home") > + .replace('\\', '/') + "/../lib/tools.jar").toURI().toURL()}, null); > + Class virtualMachine = classLoader.loadClass("com.sun.tools.attach.VirtualMachine"); > + String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); > + Object virtualMachineInstance = virtualMachine.getDeclaredMethod("attach", String.class) > + .invoke(null, runtimeName.substring(0, runtimeName.indexOf('@'))); > + try { > + File agentFile = File.createTempFile("jolAgent", ".jar"); > + try { > + saveAgentJar(agentFile); > + virtualMachine.getDeclaredMethod("loadAgent", String.class, String.class) > + .invoke(virtualMachineInstance, agentFile.getAbsolutePath(), ""); > + INSTRUMENTATION = doGetInstrumentation(); > + } finally { > + agentFile.delete(); > + } > + } finally { > + virtualMachine.getDeclaredMethod("detach").invoke(virtualMachineInstance); > + } > + } > + > + private static Instrumentation doGetInstrumentation() { > + try { > + Field field = ClassLoader.getSystemClassLoader() > + .loadClass(Installer.class.getName()) > + .getDeclaredField("instrumentation"); > + field.setAccessible(true); > + return (Instrumentation) field.get(null); > + } catch (Exception e) { > + throw null; > + } > + } > + > + private static void saveAgentJar(File agentFile) throws Exception { > + InputStream inputStream = Installer.class.getResourceAsStream('/' + Installer.class.getName().replace('.', '/') + ".class"); > + if (inputStream == null) { > + return; > + } > + try { > + Manifest manifest = new Manifest(); > + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); > + manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), Installer.class.getName()); > + JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(agentFile), manifest); > + try { > + jarOutputStream.putNextEntry(new JarEntry('/' + Installer.class.getName().replace('.', '/') + ".class")); > + byte[] buffer = new byte[1024]; > + int index; > + while ((index = inputStream.read(buffer)) != -1) { > + jarOutputStream.write(buffer, 0, index); > + } > + jarOutputStream.closeEntry(); > + } finally { > + jarOutputStream.close(); > + } > + } finally { > + inputStream.close(); > + } > + } > + > /** > * Produces the toString string, only calling toString() on known types, > * which do not mutate the instance. > @@ -526,6 +612,15 @@ > > static class MyDoubles4 { > private double f1, f2, f3, f4; > + } > + > + public static class Installer { > + > + private static volatile Instrumentation instrumentation; > + > + public static void agentmain(String agentArgs, Instrumentation inst) { > + instrumentation = inst; > + } > } > > } > > > > 2014-12-18 21:02 GMT+01:00 Aleksey Shipilev >: > > Hi Rafael, Serkan, > > On 12/17/2014 05:41 PM, Rafael Winterhalter wrote: > > But this other approach only works if VMSupport was loaded by the system > > ClassLoader where agents must be loaded from. Otherwise, the VMSupport that > > is the agent and the VMSupport that installs the agent are two different > > classes and the set INSTRUMENTATION field would belong to a different > > class. This is why I prefer the hack by adding an additional installer > > class that is minimal in byte size and does not carry any other class > > dependencies and inject this class. Also, I only access it by reflection in > > order to avoid these class identity issues. Might not be as relevant for > > JOL as I guess most people do not really use this from a servlet container > > or somewhere but I guess there might be corner cases (?). > > You will be suprised *where* people use JOL. Therefore, I would not like > to artificially limit the its applicability. > > I like Rafael's approach. Rafael, can you send the patch either in > attachment or inline on this list? OpenJDK ToU requires us to accept the > incoming changes on openjdk.java.net . You > seem to already have the OCA > signed, so we are in clear about attribution. > > Thanks, > -Aleksey. > > From rafael.wth at gmail.com Thu Dec 18 22:59:31 2014 From: rafael.wth at gmail.com (Rafael Winterhalter) Date: Thu, 18 Dec 2014 23:59:31 +0100 Subject: JOL object header information In-Reply-To: <549359D9.7030702@oracle.com> References: <549332CE.8030504@oracle.com> <549359D9.7030702@oracle.com> Message-ID: Brilliant, thanks. That took significantly less time than my glass fish patch ;) 2014-12-18 23:48 GMT+01:00 Aleksey Shipilev : > > Thank you, I have refactored this a bit, and committed: > https://bugs.openjdk.java.net/browse/CODETOOLS-7901220 > http://hg.openjdk.java.net/code-tools/jol/rev/be8776814beb > > -Aleksey. > > On 12/19/2014 01:04 AM, Rafael Winterhalter wrote: > > Hi all, sure thing. Find the patch attached. I signed the OCA a year ago > > when I patched something for glassfish. If this is valid for JOL, great, > > otherwise ping me. > > > > Index: jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java > > IDEA additional info: > > Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP > > <+>UTF-8 > > =================================================================== > > --- jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java > (revision 31:9a546334aa57fa0e114db159b2a8a5345c249b3e) > > +++ jol-core/src/main/java/org/openjdk/jol/util/VMSupport.java > (revision 31+:9a546334aa57+) > > @@ -35,13 +35,22 @@ > > import javax.management.openmbean.CompositeDataSupport; > > import java.io.PrintWriter; > > import java.io.StringWriter; > > +import java.io.InputStream; > > +import java.io.File; > > +import java.io.FileOutputStream; > > import java.lang.instrument.Instrumentation; > > import java.lang.management.ManagementFactory; > > import java.lang.reflect.Field; > > +import java.net.URL; > > +import java.net.URLClassLoader; > > import java.security.AccessController; > > import java.security.PrivilegedAction; > > import java.util.Arrays; > > import java.util.Random; > > +import java.util.jar.Attributes; > > +import java.util.jar.JarEntry; > > +import java.util.jar.JarOutputStream; > > +import java.util.jar.Manifest; > > import java.util.regex.Matcher; > > import java.util.regex.Pattern; > > > > @@ -55,6 +64,8 @@ > > > > private static Instrumentation INSTRUMENTATION; > > > > + private static boolean installAttempt; > > + > > public static final Unsafe U; > > > > public static final String VM_NAME; > > @@ -253,6 +264,7 @@ > > private final boolean exactSizeAvail; > > > > public SizeInfo(Object o, ClassLayout layout) { > > + VMSupport.installInstrumentation(); > > exactSizeAvail = VMSupport.INSTRUMENTATION != null && o != > null; > > size = exactSizeAvail ? (int) > VMSupport.INSTRUMENTATION.getObjectSize(o) : layout.instanceSize(); > > } > > @@ -418,6 +430,7 @@ > > } > > > > public static int sizeOf(Object o) { > > + installInstrumentation(); > > if (VMSupport.INSTRUMENTATION != null) { > > return VMSupport.align((int) > VMSupport.INSTRUMENTATION.getObjectSize(o)); > > } > > @@ -425,6 +438,79 @@ > > return new > CurrentLayouter().layout(ClassData.parseInstance(o)).instanceSize(); > > } > > > > + private static void installInstrumentation() { > > + if (!installAttempt) { > > + try { > > + doInstall(); > > + } catch (Exception ignored) { > > + } > > + } > > + } > > + > > + private static synchronized void doInstall() throws Exception { > > + if (installAttempt) { > > + return; > > + } > > + installAttempt = true; > > + ClassLoader classLoader = new URLClassLoader(new URL[]{new > File(System.getProperty("java.home") > > + .replace('\\', '/') + > "/../lib/tools.jar").toURI().toURL()}, null); > > + Class virtualMachine = > classLoader.loadClass("com.sun.tools.attach.VirtualMachine"); > > + String runtimeName = > ManagementFactory.getRuntimeMXBean().getName(); > > + Object virtualMachineInstance = > virtualMachine.getDeclaredMethod("attach", String.class) > > + .invoke(null, runtimeName.substring(0, > runtimeName.indexOf('@'))); > > + try { > > + File agentFile = File.createTempFile("jolAgent", ".jar"); > > + try { > > + saveAgentJar(agentFile); > > + virtualMachine.getDeclaredMethod("loadAgent", > String.class, String.class) > > + .invoke(virtualMachineInstance, > agentFile.getAbsolutePath(), ""); > > + INSTRUMENTATION = doGetInstrumentation(); > > + } finally { > > + agentFile.delete(); > > + } > > + } finally { > > + > virtualMachine.getDeclaredMethod("detach").invoke(virtualMachineInstance); > > + } > > + } > > + > > + private static Instrumentation doGetInstrumentation() { > > + try { > > + Field field = ClassLoader.getSystemClassLoader() > > + .loadClass(Installer.class.getName()) > > + .getDeclaredField("instrumentation"); > > + field.setAccessible(true); > > + return (Instrumentation) field.get(null); > > + } catch (Exception e) { > > + throw null; > > + } > > + } > > + > > + private static void saveAgentJar(File agentFile) throws Exception { > > + InputStream inputStream = > Installer.class.getResourceAsStream('/' + > Installer.class.getName().replace('.', '/') + ".class"); > > + if (inputStream == null) { > > + return; > > + } > > + try { > > + Manifest manifest = new Manifest(); > > + > manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); > > + manifest.getMainAttributes().put(new > Attributes.Name("Agent-Class"), Installer.class.getName()); > > + JarOutputStream jarOutputStream = new JarOutputStream(new > FileOutputStream(agentFile), manifest); > > + try { > > + jarOutputStream.putNextEntry(new JarEntry('/' + > Installer.class.getName().replace('.', '/') + ".class")); > > + byte[] buffer = new byte[1024]; > > + int index; > > + while ((index = inputStream.read(buffer)) != -1) { > > + jarOutputStream.write(buffer, 0, index); > > + } > > + jarOutputStream.closeEntry(); > > + } finally { > > + jarOutputStream.close(); > > + } > > + } finally { > > + inputStream.close(); > > + } > > + } > > + > > /** > > * Produces the toString string, only calling toString() on known > types, > > * which do not mutate the instance. > > @@ -526,6 +612,15 @@ > > > > static class MyDoubles4 { > > private double f1, f2, f3, f4; > > + } > > + > > + public static class Installer { > > + > > + private static volatile Instrumentation instrumentation; > > + > > + public static void agentmain(String agentArgs, Instrumentation > inst) { > > + instrumentation = inst; > > + } > > } > > > > } > > > > > > > > 2014-12-18 21:02 GMT+01:00 Aleksey Shipilev > >: > > > > Hi Rafael, Serkan, > > > > On 12/17/2014 05:41 PM, Rafael Winterhalter wrote: > > > But this other approach only works if VMSupport was loaded by the > system > > > ClassLoader where agents must be loaded from. Otherwise, the > VMSupport that > > > is the agent and the VMSupport that installs the agent are two > different > > > classes and the set INSTRUMENTATION field would belong to a > different > > > class. This is why I prefer the hack by adding an additional > installer > > > class that is minimal in byte size and does not carry any other > class > > > dependencies and inject this class. Also, I only access it by > reflection in > > > order to avoid these class identity issues. Might not be as > relevant for > > > JOL as I guess most people do not really use this from a servlet > container > > > or somewhere but I guess there might be corner cases (?). > > > > You will be suprised *where* people use JOL. Therefore, I would not > like > > to artificially limit the its applicability. > > > > I like Rafael's approach. Rafael, can you send the patch either in > > attachment or inline on this list? OpenJDK ToU requires us to accept > the > > incoming changes on openjdk.java.net . You > > seem to already have the OCA > > signed, so we are in clear about attribution. > > > > Thanks, > > -Aleksey. > > > > > > >