欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JVM系列十四(读书笔记).

程序员文章站 2022-04-15 17:05:52
在高性能硬件上部署程序,目前主要有两种方式: 1. 通过64位JDK来使用大内存。 2. 通过若干个32位虚拟机建立逻辑集群来利用硬件资源。 32位的虚拟机和64位的虚拟机部署应用有什么区别? 1. 在32位的 Windows 平台中每个进程只能使用 2GB 内存,考虑到堆以外的内存开销,堆一般最多 ......

在高性能硬件上部署程序,目前主要有两种方式:

  1. 通过64位jdk来使用大内存。
  2. 通过若干个32位虚拟机建立逻辑集群来利用硬件资源。

32位的虚拟机和64位的虚拟机部署应用有什么区别?

  1. 在32位的 windows 平台中每个进程只能使用 2gb 内存,考虑到堆以外的内存开销,堆一般最多只能开到 1.5gb;在 linux 或者 unix 系统中,可以提升到 3gb 乃至接近 4gb 的内存,但仍然受到最高 4gb(2^32) 内存的限制。使用 64 位的虚拟机可以管理更大的内存。
  2. 64位虚拟机的内存回收将导致更长的时间停顿。
  3. 现阶段,64位 jdk 的性能测试结果普遍低于32位的 jdk。
  4. 64位的 jdk 要是产生堆溢出几乎就无法产生堆存储快照(因为要产生十几 gb 乃至更大的 dump 文件),哪怕产生了快照也几乎无法进行分析。
  5. 相同程序在64位 jdk 消耗的内存一般比32位 jdk 大,这是由于指针膨胀,以及数据类型对齐补白等因素导致的。

除了java 堆、虚拟机栈和元空间以外,下面这些区域还会占用较多的内存:

  1. direct memory:直接内存,多用于 nio 操作,可通过 -xx:maxdirectmemorysize 调整大小,内存不足时抛出 outofmemoryerror。direct memory 的回收只能等待老年代满了以后 full gc,然后“顺便地”帮它清理掉内存的废弃对象,否则它只能一直等到 outofmemoryerror 时,先 catch 掉,再在 catch 块里面调用 system.gc()。
  2. socket 缓冲区:每个 socket 连接都有 receive 和 send 两个缓冲区,分别占大约 37kb 和 25kb 的内存,连接多的话这块内存占用也比较可观。如果无法分配,则可能会抛出 ioexception:too many open files 异常。
  3. jni 代码:如果代码中使用 jni 调用本地库,那本地库使用的内存也不在堆中。
  4. 虚拟机和 gc:虚拟机、gc 的代码执行也要消耗一定的内存。

破坏双亲委派模型

  1. java 中所有涉及 spi 的加载动作,比如 jndi、jdbc、jce、jaxb 和 jbi 等,都是违背了双亲委派模型来逆向使用类加载器,它利用“线程上下文类加载器”去加载所需要的 spi 代码,也就是父类加载器请求子类加载器去完成类加载的动作。
  2. 在 osgi 里面,加载器之间的关系不再是双亲委派模型的树形结构,而是进一步发展成了一种运行时才能确定的网状结构。osgi 的 bundle 类加载器之间只有规则,没有固定的委派关系。例如,某个 bundle 声明了一个它依赖的 package,如果有其他的 bundle 声明发布了这个 package 后,那么对这个 package 的所有类加载动作都会委派给发布它的 bundle 类加载器去完成。osgi 也是基于此实现模块级的热插拔功能,典型的案例就是 eclipse ide。

字节码执行引擎

  1. 字节码执行引擎是 java 虚拟机最核心的组成部分之一。
  2. 在 java 虚拟机规范中制定了虚拟机字节码执行引擎的概念模型,这个概念模型成为各种虚拟机执行引擎的统一外观(facade)。
  3. 所有 java 虚拟机的执行引擎都是一致的:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果。

tomcat 的 jsp 文件为什么可以实现热替换?

tomcat 自定义了 commonclassloader、catalinaclassloader、sharedclassloader 和 webappclassloader 四种类加载器,分别加载 /common/*、/server/*、/shared/* 和 /webapp/web-inf/* 中 java 类库的逻辑。其中 webapp 类加载器和 jsp 类加载器通常会存在多个实例,每一台 web 应用程序对应一个 webapp 类加载器,每一个 jsp 文件对应一个 jsp 类加载器,jsp 类加载器的加载范围仅仅是这个 jsp 文件所编译出来的那一个 class,它出现的目的就是为了被丢弃:当服务器检测到 jsp 文件被修改时,会替换掉目前的 jsp 类加载器的实例,并通过再建立一个新的 jsp 类加载器来实现 jsp 文件的热替换。

JVM系列十四(读书笔记).

jdk 的每次版本升级,新增的功能大致可以分为下面四类:

  1. 在编译层面的改进。如自动装箱拆箱、变长参数、泛型等。
  2. java api 的代码增强。如 collections、java.util.concurrent 并发包等。
  3. 需要在字节码层面支持的改动。如升级版本号之类。
  4. 虚拟机内部的改动。这类改动对于程序员编写代码基本是透明的,但会对程序运行时产生影响。

其他

  1. 学习 jee 规范,去看 jboss 源码;学习类加载器,就去看 osgi 源码。
  2. 动态代理中所谓的“动态”,是针对使用 java 代码实际编写了代理类的 “静态”代理而言的,它的优势不仅在于省去了编写代理类那一点工作量,而是实现了可以在原始类和接口还未知的时候,就确定代理类的代理行为,当代理类与原始类脱离直接联系后,就可以很灵活地重用于不同的应用场景之中。