一、问题背景
itask中线上20几个task,这些task的大多数都有这么一些特点:
1.基于quartz和spring框架,配置信息已经硬编码在xml配置中
2.执行的时候一个任务启动一个jvm线程,然后加载spring容器,quartz配置在spring容器中
3.实际执行处理数据的时候大概需要512M空间或者更多
4.这些任务每天只触发执行数据处理几次,一般在6-10次左右,每次执行的时间大都在5-10分左右。
为了更好的利用机器的内存资源,个人认为可以将业务相关的一组任务在执行时间不相互冲突的情况下合并到一个jvm中。有些同学反映,合并后同一个jvm中的任务就不能单独重启或者关闭了。
二、初步方案
系统中现有一个合并方案,该合并方案是将所有的任务放到一个spring容器中了,然后配置多个quartz的trigger来实现的。显然这种情况先任务是不可以单独重启或者关闭的。尤其是当其中一个任务有新的发布更新的时候必须将这一组任务全部重启。这样就带了不必要的麻烦。
因此,我们仔细考虑了这个问题,并提出了三个解决方案(现在还没有确定最终方案,不过最终方案于本文的分享内容没有关系)。在讨论这个方案的时候发现一个非常好玩的技术点。在此跟大家分享下。
其中一个轻量级的方案是:将现有的一个任务进程转换成同一个jvm中的一个线程,然后在该线程内加载并启动该任务的spring容器。同时为了能够支持单独启动或者关闭某个任务,我们需要在这个jvm线程开启一个socket服务端口,主要用来侦听其他进程发来的启动关闭命令。由于遗留任务较多,这一解决方案可以最大化的减少遗留任务的改造。
三、方案难点解决
但是这个方案上有一个难点,就是当其中一个任务需要用新发布的jar包时,如果jvm不重启,是无法重新加载这个更新的jar包的。当然这也是jvm规范对一个well-behaved的classloader所要求的(见jvm规范5.3节末尾,参考链接http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html#jvms-5.3)。同样我们在jdk的classLoader的实现代码也能验证这一点(见下图291行处)。
四、解决办法:
找到了问题所在也就基本解决了这个问题,可以从两个地方分别找到这个问题的答案。
一是jvm的规范中。jvm规范在提到“At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. ”也就是说我们只需要是使用不同的classloader再去装载这个class,那么这个class就可以被重新从磁盘读入了。
我们知道默认的java类在jvm中的加载是通过启动器类加载器、扩展类加载器、系统类加载器以双亲委托的方式完成的。而这些类加载器在同一个jvm中一般以单例的形式实现的。所以我们必须编写自己的类加载器。而该类加载器游必须与默认的系统类加载器的功能完全一样。在我们所使用的jvm中系统类加载器实际上一般就等同于URLClassloarder所以我们可以直接继承该类编写我们自己的类加载器。代码如下:
class MyClassLoader extends URLClassLoader {//为了防止被滥用,此类的访问权限控制的越强越好 private static URLClassLoader scl = (URLClassLoader) getSystemClassLoader(); private MyClassLoader() { super(scl.getURLs(), null);//大家可以想想此处的parent为什么指定为null } static ClassLoader getAnotherSysClassLoader() { return new MyClassLoader(); } }
完整的参考代码见链接:http://taft.iteye.com/blog/1839825
相关推荐
深入JVM概要 JVM详解 本文将详细介绍Java虚拟机(JVM)的内部机理和实现...JVM中的类型的生命周期、方法区、常量池、类加载器、垃圾收集器、栈和局部变量等都是JVM的重要组件,它们共同构成了Java虚拟机的基本架构。
1. **加载**:当Java应用程序启动时,JVM首先通过类加载器加载主类(即包含main方法的类)。类加载器根据类的全限定名查找对应的.class文件,然后将其加载到内存中。类加载器有三种:bootstrap class loader(引导类...
以上只是JVM众多知识中的一部分,实际上,JVM涉及的领域还包括内存模型、线程管理、异常处理、类加载策略等。理解JVM的工作原理对于编写高效、稳定的Java程序至关重要。通过研究这个压缩包中的资源,你可以更深入地...
3. 指令集:JVM使用一套基于栈的指令集,这些指令对应于字节码,如`aload`用于加载引用到操作数栈,`iadd`用于执行整数加法等。 4. 执行引擎:解释器负责逐条解释执行字节码,而即时编译器(JIT)会将热点代码编译...
JVM的主要职责包括加载Java程序、验证字节码、将字节码转换成机器码执行、内存管理、垃圾回收和提供安全机制等。JVM的内存管理主要分为堆(Heap)、栈(Stack)、本地方法栈(Native Method Stack)、方法区(Method...
首先,它具备一种名为“类加载器”(Class Loader)的组件,用于加载和管理程序中的类文件。类加载器不仅能够按需加载类文件,还能够支持热更新等功能。此外,类之间的隔离也使得每个类的运行环境相对独立,提高了...
1. **类的加载机制**:这是JVM的基础,负责加载Java类,并准备执行这些类。类加载机制确保了类的正确加载,并管理类的生命周期。 2. **JVM内存结构**:主要包括堆、栈、方法区等,用于存储和管理数据。 3. **GC...
类加载器子系统是 JVM 的一个重要组成部分,它负责加载 Java 类文件,并将其转换为 JVM 可以识别的字节码。类加载器子系统包括启动类加载器、扩展类加载器、系统类加载器和用户自定义加载器四个部分。它们分别负责...
这个过程确保了只有正确无误的类能够被加载到JVM中。 ### 内存管理 1. **堆内存**:所有对象都在堆中创建,JVM通过垃圾收集机制自动回收不再使用的对象。 2. **栈内存**:每个线程都有自己的栈,用于存储局部变量表...
类加载器负责加载类到JVM中。主要有Bootstrap ClassLoader、Extension ClassLoader和App ClassLoader,以及用户自定义的类加载器。类加载器遵循双亲委托模型,确保类的唯一性。 以上是JVM的一些核心概念和工作机制...
- JVM在运行过程中,将频繁执行的热点代码编译成机器码,提高执行效率。 10. **异常处理**: - JVM如何处理运行时异常,如栈展开(Stack Unwinding)过程。 这些知识点覆盖了JVM的基础到进阶内容,适合初学者和...
在《JVM指令手册》中,主要涵盖了栈和局部变量的操作,这是理解JVM工作原理的关键部分。 1. 栈和局部变量操作: JVM使用栈来存储临时计算结果,局部变量表则是存储方法参数和局部变量的地方。以下是一些主要的指令...
首先,JVM指令手册中提到的操作栈和局部变量的指令分为两大类:常量压栈指令和局部变量加载指令。常量压栈指令用于将各种类型的常量值(null, int, long, float, double, char, byte, short)压入操作数栈。例如,a...
2. 双亲委派模型:在类加载过程中,JVM采用双亲委派模型,避免类的重复加载和保证类的全局一致性。 四、JVM性能优化 1. 字符串常量池:Java 11优化了字符串常量池的实现,提高了字符串操作的效率。 2. 动态编译:...
1. **类装载器(ClassLoader)**:负责查找和加载类文件到JVM内存中。 2. **运行时数据区(Runtime Data Area)**:包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。 3. **执行引擎(Execution Engine)**:执行...
JVM通过解析.class文件中的字节码,将其转换为机器码,从而在本地操作系统上执行。理解JVM的工作机制对于优化Java应用程序性能至关重要。 二、开源项目的意义 开源项目“jvmjava”为开发者提供了一种学习JVM内部...
本课程的PPT旨在深入讲解JVM的工作原理、内存管理、性能优化等相关知识,帮助学员提升对JVM的理解并能应用于实际开发中。 一、JVM概述 Java虚拟机作为一个抽象的计算机,它负责解析字节码并执行Java程序。JVM的主要...
- **概述**:类加载器是JVM中负责动态加载类文件的重要组件,它将类文件中的数据读取到内存中,并转换为可供JVM使用的数据结构。 - **分类**:JVM中存在多种类型的类加载器,主要包括启动类加载器、扩展类加载器和...
1. **操作数栈管理指令**:JVM中的每条指令都可能涉及到操作数栈的操作,如`iconst`系列用于将整数值压入栈,`pop`和`pop2`用于弹出栈顶元素,`dup`用于复制栈顶元素并将其推回栈顶。 2. **局部变量表操作指令**:...
- **指针压缩**:在64位JVM中,-XX:+UseCompressedOops选项默认开启,以减小对象指针的大小,节省内存。 - **内存结构**:包括堆(新生代、老年代)、栈(方法区、本地方法栈)、PC寄存器和方法区(包含运行时常量...