因为语言的特性,Java不需要开发者手动回收内存,这部分工作由JVM来完成,至于何时回收需要回收的对象,从理论上来说最好的时机是在对象失去引用的时候,但是做到这一点对性能影响颇大,所有Java选择了另一种方法,那就是周期性去遍历所有对象,找出需要回收的对象然后做回收操作。
正如上文所说,对象失去引用在回收线程发现它之前仍将存在一段时间,但是Java希望没用的对象能尽快被回收,比较简单的方式是提高回收线程的执行频率,但是这将导致性能问题,对象的生命周期内将被检查多次,生命周期长的对象将被无谓的多次被检查。为了权衡两者的关系,这才催生了另一个概念:分代,不同生命周期的对象分别放在不同的区域,不同区域的回收频率不同,这大大提高系统效率。
CMS有何缺点?
CMS模式下何时会触发FullGC?
除根加载器外,每个类加载器都有父加载器,当加载某个类时首先让父加载器(加载器链路)们尝试加载,如果父加载器们加载失败,则捕获异常并调用自己的findClass方法尝试加载。
依赖顺序:自定义加载器->系统加载器->扩展加载器->根加载器。
用户自定义加载器需要继承抽象类ClassLoad,创建自定义加载器时可以指定父加载器,默认的父加载器为系统加载器,如果指定为空则父加载器为根加载器。
JVM运行过程中遇到了需要加载的类,由当前类的定义类加载器(加载当前类的加载器)来加载。
每个加载器都有自己的命名空间,命名空间由该加载器和所有父加载器加载的类构成的,可以理解为同一个类加载系统。同一个命名空间中,只存在一个名称及包名相同的Class实例,同一个命名空间内才允许类之间相互访问。
JVM之所以使用父委托机制来实现类加载,主要出于安全考虑,在同一个加载器系统中不存在同一个类名、包名相同的类,一个同样类名、包名的类不会加载第二次,因此体系中已经被加载的系统类不会被恶意代码篡改。
定义:相同包名且由同一加载器加载的一部分类。
如果有在同一加载器系统中包名相同但由不同类加载器加载的类,他们不在同一个运行时包,所以理论上不具有相同包的权限。
运行时包的存在同样是出于安全考虑。
如何实现自定义加载器?
调用抽象类ClassLoad的loadClass方法时会调用parent的loadClass方法,如果parent为空则调用根加载器的loadClass,如果父加载器方法抛出异常则调用自己的findClass方法,
该方法在ClassLoad类中默认抛出ClassNotDeError,用户需要自己实现相关find class逻辑。ClassLoad中的defineClass方法可以通过class文件的二进制数据初始化为Class对象。
JavaEE的类加载器默认行为是首先在Bootstrap中加载,如果加载不到则先从Webapp下面加载。JavaEE规范推荐每个模块的类加载器先加载本类加载的内容,如果加载不到才回到parent类加载器中尝试加载。
Tomcat有自定义的类加载器,父加载器为根加载器,加载时会首先加载应用下的lib,然后再加载tomcat下的lib。
JavaEE的 委派模型:
加载、连接、初始化:
连接阶段:
当翻阅某些互联网公司的技术架构图时,可能会发现他们当中很多有一个共同的特点,那就是应用与数据库之间有一所谓的“数据代理层”(比如美团、58同城、早期的淘宝等),至于数据代理层存在的价值,一般都会谈到以下两点:
然而为实现数据代理层所付出的代价也是相当可观的,不仅需要增加该层的硬件设施、增加人员维护,由于应用层与数据层之间的传输协议普遍性能不高,与MySQL自己的二进制专用协议相比,无论在序列化性能还是数据包大小都有较大差距,因此应用层需要付出更多的代价去与数据层交互。以上这些缺点对于具有海量业务的公司来说似乎不可容忍,有没有可以解决以上问题的方式呢,答案是肯定的。
首先了解一下淘宝的TDDL。
TDDL是淘宝应用于分库分表的项目,经过多个版本的发展,整合阿里另一个项目”CORBA”之后愈发强大。TDDL主要提供分库分表场景下动态访问路由、数据合并、流控等功能。因为TDDL在代码层面被项目依赖,依托”CORBA”强大的SQL解析能力,领域模型定位于数据库与JDBC之间,所以对业务代码无侵入,基本上实现了上文中数据层的第一个任务。
可以说如果没有MySQL线程池的话,TDDL没有任何意义,因为在TDDL模式下,应用层需要直连数据库,对上文中数据层的第二个任务并不是TDDL的能力范围,需要借助线程池来解决MySQL海量连接问题。
数据库线程池并不是MySQL的独门绝技,在5.5时代MariaDB和PerconaDB就已经实现了线程池功能,MySQL在随后的5.6社区版本当中也加入了该功能。
在MySQL5.6之前,线程模型比较简单,类似于Java的BIO模型,每个线程处理只能处理一个连接,每次MySQL请求的数据IO、业务响应都在同一个线程当中。如果集群庞大的分库分表场景下,MySQL将会产生大量的TCP连接,系统会耗费大量的时间用来做线程上下文切换、缓存换入换出以及资源竞争,如果并发量陡增(比如电商系统的秒杀场景),MySQL将直接无响应。
MySQL通过线程池所实现的线程模型与当今主流IO系统的线程模型基本一致(如Mina、Netty、Tomcat、Nginx等),简要来说就是一部分线程负责网络数据包的IO(IO线程:负责在核心态内存与用户态内存间交换数据),它们每次接受SQL请求并将任务加入队列之后立即返回,另一部分线程负责响应请求(业务线程),不断从队列获取任务并执行。IO线程使用非阻塞模型(epoll),可以创建海量连接且保持性能稳定,由于与业务线程独立,当业务线程繁忙时不会影响IO响应。两部分线程之间有队列负责缓冲任务,保护数据库引擎不会在短时间内涌入太多任务,保证正常运行。

每一个绿色的方框代表一个group,group的数量由thread_pool_size参数决定。
每个group包含一个普通队列和一个优先队列,包含一个listen线程和若干worker线程,两种线程间可以动态转换,worker线程数量由工作负载决定,同时也受thread_pool_oversubscribe参数影响。普通队列中的任务超过一定时间未被执行会被列入优先队列,而优先队列的任务会被优先执行。
整个group组有一个timer监控线程。
三星级索引
选择性
什么情况下无法使用索引
新博客:GitHub + Hexo
1 | Node.js |
1 | 生成密钥:ssh-keygen -t rsa -C "911@zhaoqun911.cn" |
1 | npm install -g hexo |
1 | cd public |
1 | _config.yml: |