Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK compact profile support #497

Closed
penberg opened this issue Sep 14, 2014 · 5 comments
Closed

JDK compact profile support #497

penberg opened this issue Sep 14, 2014 · 5 comments

Comments

@penberg
Copy link
Contributor

penberg commented Sep 14, 2014

Java 8 introduced "compact profiles" which are stripped down versions of the JDK:

http://openjdk.java.net/jeps/161

We should provide an OSv image with one of the compact profiles to reduce the size of JDK-based VM images which currently weight at around 120 MiB. That's insanely large when compared to something like Node.js which has base images just under 20 MiB.

@wkozaczuk
Copy link
Collaborator

I have made some progress on trying to build and run an image with Java 8 compact profile more specifically compact1.
As I was testing it I realized that some code in RunJava related java code relies on classes that are NOT part of any compact 1, 2, or 3 profile. More specifically there is dependency on java.beans.

Here is an output from running simple hello world example in Quemu on Mac:

reated instance: capstan-java8-compact-example
WARNING: aio=native was specified for '/Users/wkozaczuk/.capstan/instances/qemu/capstan-java8-compact-example/disk.qcow2', but is not supported in this build. Falling back to aio=threads.
This will become an error condition in future QEMU versions.
WARNING: aio=native was specified for '/Users/wkozaczuk/.capstan/repository/capstan-java8-compact-example/capstan-java8-compact-example.qemu', but is not supported in this build. Falling back to aio=threads.
This will become an error condition in future QEMU versions.
OSv v0.24
eth0: 192.168.122.15
java.so: Failed to load io/osv/RunJava
Exception in thread "main" java.lang.NoClassDefFoundError: java/beans/IntrospectionException
at io.osv.shade.net.sf.cglib.core.KeyFactory$Generator.generateClass(KeyFactory.java:166)
at io.osv.shade.net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at io.osv.shade.net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at io.osv.shade.net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:144)
at io.osv.shade.net.sf.cglib.core.KeyFactory.create(KeyFactory.java:116)
at io.osv.shade.net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)
at io.osv.shade.net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)
at io.osv.shade.net.sf.cglib.proxy.Enhancer.(Enhancer.java:69)
at io.osv.ContextIsolator.installSystemPropertiesProxy(ContextIsolator.java:80)
at io.osv.ContextIsolator.(ContextIsolator.java:70)
at io.osv.ContextIsolator.(ContextIsolator.java:33)
at io.osv.OsvSystemClassLoader.getContext(OsvSystemClassLoader.java:57)
at io.osv.OsvSystemClassLoader.getDelegate(OsvSystemClassLoader.java:61)
at io.osv.OsvSystemClassLoader.loadClass(OsvSystemClassLoader.java:70)
Caused by: java.lang.ClassNotFoundException: java.beans.IntrospectionException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 14 more

Can somebody shed light or point to some wiki page to why there is a need for class loader isolation and dependency on cglib? Maybe all that can be reworked so that RunJava does not depend on java.beans.* and cglib.

Here is some info from the compact profile wiki:
"In a few rare cases it may be necessary to subset classes by removing methods, e.g., the addPropertyChangeListener and removePropertyChangeListener methods defined by java.util.logging.LogManager, to avoid spliting packages or referencing types that do not exist.

JMX and the JMX Remote API are proposed for compact3. It may be necessary to update the JMX API to avoid referencing types in java.beans that do not exist. In the case of the JMX Remote API then it may be necessary to downgrade support for the RMI-IIOP protocol to avoiding needing to include CORBA."

@nyh
Copy link
Contributor

nyh commented May 29, 2016

@tgrabiec is more familiar with the details here, but to make a long story short: We wanted to be able to run several different Java programs on the same JVM and give those different programs some semblance of running on a different JVM - different class loaders, different loggers, and so on.

This isolation feature was especially important when we had a shell and ssh written in Java running on every OSv instance, which is no longer the case, so if you only plan to run one Java application on OSv, I think your best bet would be to remove this isolation feature - and its depedency on cglib. We could have an alternative version of the RunJava code without isolation (which would more-or-less reverse @tgrabiec 's patches adding isolation), or perhaps it might be possible to have one code which supports both options.

@wkozaczuk
Copy link
Collaborator

I managed to build custom compact profile1 capstan image and run a "hello world" app. Essentially I created an app directory under apps modeled after apps/openjdk8-fedora and adjusted Makefile to make it pull JRE custom compact profile1 tarballs from my personal S3 bucket. As far as custom compact profile goes I ended up building openjdk-1.8.0.92.b14 custom profile1 and doing following surgery on it:

  • add java.beans.* and com/sun/beans/* from full JRE to lib/rt.jar
  • add /com/sun/beans/ to lib/meta-index file
  • replace java/util/logging/LogManager.class with version from full JRE so it has required addPropertyChangeListener() method.

All that I based on following advise from stackoverflow.com - http://stackoverflow.com/questions/23907728/how-to-use-log4j-in-embedded-jdk-compact-1-2-3

As you can see this hack is not ideal and makes me think what is the right path to move forward with support of compact profiles specifically and JVM (not only Java) apps on OSv platform in general given following:

  • Java 9 is going to make JVM apps modular and possibly more compact
  • LogManager.addPropertyChangeListener() is deprecated in Java 8 and will be gone in Java 9
  • most modern JVM app (Java, Scala, Clojure, Kotlin) tend to be microservices or at least "one-thing focused apps" which do not required running multiple isolated apps on single JVM

Here are my questions regarding support of JVM apps on OSv going forward:

  1. Should it support the classloader isolation?
  2. Is there any reason for any *.java source code to support JVM apps besides classloader isolation?
  3. Is there still any reason to treat JRE in special way by having special JVM launcher (java/jvm/java.cc) and other C++ code under /java folder?
  4. Could JVM apps be built as simply as other native apps (say apps/redis as example) or there is something special about JVM that requires special support in OSv and that is a reason for /java folder?

It seems there is a lot of complexity that may not be necessary anymore. I am very interested in simplifying that but I need some guidance as far as what to keep under /java and what can be removed. And there are possibly many reasons (optimizations like balooning) which may require some of this complexity going forward. Can @tgrabiec offer some help here?

Also I have found an issue #623 which may get addressed if we simplify JVM support.

@nyh
Copy link
Contributor

nyh commented Jun 1, 2016

On Wed, Jun 1, 2016 at 11:32 PM, wkozaczuk [email protected] wrote:

I managed to build custom compact profile1 capstan image and run a "hello
world" app. Essentially I created an app directory under apps modeled after
apps/openjdk8-fedora and adjusted Makefile to make it pull JRE custom
compact profile1 tarballs from my personal S3 bucket. As far as custom
compact profile goes I ended up building openjdk-1.8.0.92.b14 custom
profile1 and doing following surgery on it:

  • add java.beans.* and com/sun/beans/* from full JRE to lib/rt.jar
  • add /com/sun/beans/ to lib/meta-index file
  • replace java/util/logging/LogManager.class with version from full
    JRE so it has required addPropertyChangeListener() method.

All that I based on following advise from stackoverflow.com -
http://stackoverflow.com/questions/23907728/how-to-use-log4j-in-embedded-jdk-compact-1-2-3

As you can see this hack is not ideal and makes me think what is the right
path to move forward with support of compact profiles specifically and JVM
(not only Java) apps on OSv platform in general given following:

  • Java 9 is going to make JVM apps modular and possibly more compact
  • LogManager.addPropertyChangeListener() is deprecated in Java 8 and
    will be gone in Java 9
  • most modern JVM app (Java, Scala, Clojure, Kotlin) tend to be
    microservices or at least "one-thing focused apps" which do not required
    running multiple isolated apps on single JVM

I agree with this sentiment.

Here are my questions regarding support of JVM apps on OSv going forward:

  1. Should it support the classloader isolation?

I think that if this causes problems, it would be really nice to make this
optional, either as a java.so option or a separate java.so binary.
I don't know how easy it is to take out the isolation stuff from java.cc
and/or RunJava.java. I guess it should be probably be easy (you can use
"git blame" and similar to find in which commits these were added, and
think how to revert them).

  1. Is there any reason for any *.java source code to support JVM apps

    besides classloader isolation?

I didn't understand this question?

  1. Is there still any reason to treat JRE in special way by having special
    JVM launcher (java/jvm/java.cc) and other C++ code under /java folder?

No, it should probably be in modules/java (we already have such a
directory).

  1. Could JVM apps be built as simply as other native apps (say apps/redis
    as example) or there is something special about JVM that requires special
    support in OSv and that is a reason for /java folder?

No, the main reason is historic reasons: the JVM was our main focus and we
always wanted to compile it and test it. This is no longer the case.

It seems there is a lot of complexity that may not be necessary anymore.

I don't know if the "isolation" thing is not necessary anymore: I was never
a big fan of it, but some people were. If you could make this part
optional, perhaps by choosing between two versions of RunJava.java, that
would be great. You can see the git history of what RunJava.java looked
like before it acquired the isolation cruft^H^H^H^Hfeature.

I am very interested in simplifying that but I need some guidance as far as

what to keep under /java and what can be removed. And there are possibly
many reasons (optimizations like balooning) which may require some of this
complexity going forward. Can @tgrabiec https://github.com/tgrabiec
offer some help here?

I don't think Ballooning is related to the issues we're discussing here. We
should leave that be (and leave its files in java/), it's an orthogonal
feature.

Indeed most of the stuff should be moved from java/ to modules/java.
There's even a comment about it in the Makefile.

Also I have found an issue #623

#623 which may get
addressed if we simplify JVM support.


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#497 (comment),
or mute the thread
https://github.com/notifications/unsubscribe/AAjqIxDTb0o-mv_wcKOyzidmtQF94ZYpks5qHexfgaJpZM4Chz0Z
.

@wkozaczuk
Copy link
Collaborator

I created pull request to address this issue. Please note that I have not had chance yet to find some official compact profile 1,2 or 3 JRE to write a unit test verifying that indeed one can run java app on any of these compact profile.

I built JDK8 compact profiles myself and used for my one manual tests and things look good. Also please note that jolokia plugin/agent relies on JMX which is only part of compact profile 3 and up so probably this part will not work with compact profiles 1 and 2 and I did not verify that.

I am also planning to work on reorganizing java folder and moving it to modules/java and modules/java-tests but that would be part of a different issue which maybe already exists.

wkozaczuk added a commit to wkozaczuk/osv that referenced this issue Aug 9, 2016
… bootstrap code under runjava cannot depend on java.beans.* that is not part of any of the compact profiles. More specifically runjava depends on cglib and asm java libraries that manipulate bytecode and rely on java.beans.

Therefore the changes that are part of this commit essentially allow to bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation between potential multiple apps and runjava code and apps that possibly targets multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager isolation and targets single main method apps on JVM in OSv and allows using compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava and refactored ContextIsolator to create JvmApp, NonIsolatedJvmApp, RunNonIsolatedJvmApp, solatedJvmApp, NonIsolatedJvmApp

    * Changed java.cc and makefile to support producing two executable - old java.so that can run multiple JVM apps in isolated fashion (class loader, log manager, etc) and new java_non_isolated.so that can run single JVM app without any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - isolated or nonisolated one; fixed Makefile to properly handle building of java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes cloudius-systems#497

Signed-off-by: Waldemar Kozaczuk <[email protected]>
wkozaczuk pushed a commit to wkozaczuk/osv that referenced this issue Aug 11, 2016
…a bootstrap code under runjava cannot depend on java.beans.* that is not part of any of the compact profiles. More specifically runjava depends on cglib and asm java libraries that manipulate bytecode and rely on java.beans*.

Therefore the changes that are part of this commit essentially allow to bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation between potential multiple apps and runjava code and apps that possibly targets multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager isolation and targets single main method apps on JVM in OSv and allows using compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava and refactored ContextIsolator to create Jvm, NonIsolatedJvm, RunNonIsolatedJvmApp, IsolatedJvm, RunIsolatedJvmApp classes

    * Changed java.cc and makefile to support producing two executable - old java.so that can run multiple JVM apps in isolated fashion (class loader, log manager, etc) and new java_non_isolated.so that can run single JVM app without any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - isolated or nonisolated one; fixed Makefile to properly handle building of java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes cloudius-systems#497

Signed-off-by: Waldemar Kozaczuk <[email protected]>
wkozaczuk pushed a commit to wkozaczuk/osv that referenced this issue Aug 12, 2016
…manager isolation in order to run JRE compact profiles.

In order to run a JVM app using compact profile 1, 2 or 3 JRE the Java bootstrap code under runjava cannot depend on java.beans.* that is not part of any of the compact profiles. More specifically runjava depends on cglib and asm java libraries that manipulate bytecode and rely on java.beans*.

Therefore the changes that are part of this commit essentially allow to bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation between potential multiple apps and runjava code and apps that possibly targets multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager isolation and targets single main method apps on JVM in OSv and allows using compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava and refactored ContextIsolator to create Jvm, NonIsolatedJvm, RunNonIsolatedJvmApp, IsolatedJvm, RunIsolatedJvmApp classes

    * Changed java.cc and makefile to support producing two executable - old java.so that can run multiple JVM apps in isolated fashion (class loader, log manager, etc) and new java_non_isolated.so that can run single JVM app without any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - isolated or nonisolated one; fixed Makefile to properly handle building of java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes cloudius-systems#497

Signed-off-by: Waldemar Kozaczuk <[email protected]>
wkozaczuk added a commit to wkozaczuk/osv that referenced this issue Aug 12, 2016
…manager isolation in order to run JRE compact profiles.

In order to run a JVM app using compact profile 1, 2 or 3 JRE the Java bootstrap code under runjava cannot depend on java.beans.* that is not part of any of the compact profiles. More specifically runjava depends on cglib and asm java libraries that manipulate bytecode and rely on java.beans*.

Therefore the changes that are part of this commit essentially allow to bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation between potential multiple apps and runjava code and apps that possibly targets multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager isolation and targets single main method apps on JVM in OSv and allows using compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava and refactored ContextIsolator to create Jvm, NonIsolatedJvm, RunNonIsolatedJvmApp, IsolatedJvm, RunIsolatedJvmApp classes

    * Changed java.cc and makefile to support producing two executable - old java.so that can run multiple JVM apps in isolated fashion (class loader, log manager, etc) and new java_non_isolated.so that can run single JVM app without any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - isolated or nonisolated one; fixed Makefile to properly handle building of java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes cloudius-systems#497

Signed-off-by: Waldemar Kozaczuk <[email protected]>
myechuri pushed a commit to myechuri/osv that referenced this issue Jun 22, 2017
…manager isolation in order to run JRE compact profiles.

In order to run a JVM app using compact profile 1, 2 or 3 JRE the Java bootstrap code under runjava cannot depend on java.beans.* that is not part of any of the compact profiles. More specifically runjava depends on cglib and asm java libraries that manipulate bytecode and rely on java.beans*.

Therefore the changes that are part of this commit essentially allow to bootstrap a JVM app in one of two modes:
      - old one which provides classloader and JUL log manager isolation between potential multiple apps and runjava code and apps that possibly targets multi-apps on single JVM in OSv and requires full JRE
      - new one which does NOT provide any classloader and JUL log manager isolation and targets single main method apps on JVM in OSv and allows using compact profile 1, 2 or 3

    Following changes are part of this commit:

    * Added io.osv.isolated and io.osv.nonisolated packages under java/runjava and refactored ContextIsolator to create Jvm, NonIsolatedJvm, RunNonIsolatedJvmApp, IsolatedJvm, RunIsolatedJvmApp classes

    * Changed java.cc and makefile to support producing two executable - old java.so that can run multiple JVM apps in isolated fashion (class loader, log manager, etc) and new java_non_isolated.so that can run single JVM app without any isolation of the former one

    * Changed java/jvm/java.cc to print which java class it uses to bootstrap - isolated or nonisolated one; fixed Makefile to properly handle building of java_non_isolated.so

    * Added java_non_isolated.so to modules/java-tests/usr.manifest

    * Added java_non_isolated test to test.py; modified testing.py to detect failure to start *.so

    * Added unit tests to test running non-isolated JVM app to tests-isolates

Fixes cloudius-systems#497

Signed-off-by: Waldemar Kozaczuk <[email protected]>
Message-Id: <[email protected]>
Signed-off-by: Avi Kivity <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants