Java内存模型5
需要注意的是,Java 运行时为所有 Java 应用程序创建的 3 个默认类加载器(?bootstrap、extension?和?application?)都不可能满足这些条件,因此,任何系统类(比如 java.lang.String)或通过应用程序类加载器加载的任何应用程序类都不能在运行时释放。即使类加载器适合进行收集,运行时也只会将收集类加载器作为 GC 周期的一部分。一些实现只会在某些 GC 周期中卸载类加载器,也可能在运行时生成类,而不去释放它。许多 Java EE 应用程序使用 JavaServer Pages (JSP) 技术来生成 Web 页面。使用 JSP 会为执行的每个 .jsp 页面生成一个类,并且这些类会在加载它们的类加载器的整个生存期中一直存在 —— 这个生存期通常是 Web 应用程序的生存期。另一种生成类的常见方法是使用 Java 反射。反射的工作方式因 Java 实现的不同而不同,当使用?java.lang.reflect?API 时,Java 运行时必须将一个反射对象(比如 java.lang.reflect.Field)的方法连接到被反射到的对象或类。这可以通过使用 Java 本机接口(Java Native Interface,JNI)访问器来完成,这种方法需要的设置很少,但是速度缓慢,也可以在运行时为您想要反射到的每种对象类型动态构建一个类。后一种方法在设置上更慢,但运行速度更快,非常适合于经常反射到一个特定类的应用程序。Java 运行时在最初几次反射到一个类时使用 JNI 方法,但当使用了若干次?JNI 方法之后,访问器会膨胀为字节码访问器,这涉及到构建类并通过新的类加载器进行加载。执行多次反射可能导致创建了许多访问器类和类加载器,保持对反射对象的引用会导致这些类一直存活,并继续占用空间,因为创建字节码访问器非常缓慢,所以 Java 运行时可以缓存这些访问器以备以后使用,一些应用程序和框架还会缓存反射对象,这进一步增加了它们的本机内存占用。
4)JNI JNI支持本机代码调用Java方法,反之亦然,Java运行时本身极大依赖于JNI代码来实现类库功能,比如文件和网络I/O,JNI应用程序可以通过三种方式增加Java运行时对本机内存的使用: