测试样例:(这个例子也可以说明为什么静态代码块,在没有对类进行实例化之前也可用)
public class Quter { static{ System.out.println("父类静态代码块"); } { System.out.println("父类代码块"); } public Quter() { System.out.println("父类构造函数"); } } import java.util.Scanner; public class Test extends Quter{ static{ System.out.println("子类类静态代码块"); } { System.out.println("子类类代码块"); } public Test() { System.out.println("子类类构造函数"); } public static void main(String[] args) { Test test = new Test(); } }定义:
是一块很小的内存空间,我们可以这样认为:当前线程正在执行的字节码的行号指示器 它记录的是地址(当前线程正在执行的字节码) 注意: 若当前线程正在执行的是一个本地方法,此时程序计数器为空。作用:
1》 字节码解释器通过改变程序计数器来一次读取指令,从而实现流程控制。
2》多线程情况下,程序计数器记录当前执行线程的地址,从而使线程来回切换。
特点:
1>一块较小的内存区域 2>线程私有。每一个线程都有一个程序计数器 3>唯一一个不会出现内存溢出的区域 4>生命周期,与线程同生共死定义
Java虚拟机栈:描述Java方法运行过程的内存模型,它会为每一个即将运行的Java方法创建一个**“栈帧”这块区域用来存储该方法运行时所需的一些信息。包括: 局部变量表(存放基本数据类型,引用数据类型,returnAddress类型变量) 操作数栈,动态链接,方法出口信息等。 当方法被执行,首先创建一个栈帧**,运行时将局部变量值存入栈帧的局部变量表中,执行完毕后,释放。
特点
1》局部变量表,与方法同生共死。它的大小在编译时就决定了,运行过程中大小不会改变。
2》虚拟机栈会出现以下两种异常:StackOverFlowError和OutOfMemoryError StackOverFlowError(内存溢出):若虚拟机栈的内存不允许动态扩展,若果线程请求栈的深度超过当前虚拟机栈最大深度时,就会出现StackOverFlowError。 OutOfMemoryError(内存溢出):若虚拟机栈的内存允许动态扩展,且当线程请求栈时内存用完了,就无法扩展会出现OutOfMemoryError。 异同: StackOverFlowError:当前线程申请的栈超过了实现定义好栈的最大深度,但内存空间还有很多。 OutOfMemoryError:指的是当前申请的栈发现栈已经满了,而且内存也用光了。 3》虚拟机栈也是线程私有的,与线程同生同死。
与Java虚拟机栈功能类似,唯一不同的就是本地方法区是在本地方法执行时的内存模型。
定义:用来存放对象的区域,几乎所有对象都存放在堆中。
特点: 1>线程共享 整个虚拟机只有一个堆,所有的线程都访问一个堆,而程序计数器,虚拟机栈,本地方法栈时一个线程一个
2>在虚拟机启动时创建
3>垃圾回收的主要场地
4>进一步细分:新生代,老年代。 新生代又可分为: Eden,From Survior,To Survior 不同区域存放具有不同的生命周期的对象。可以根据不同区域使用不同的垃圾回收算法,会更加高效。
5>堆的大小即可以固定也可以扩展,但主流的虚拟机是可以扩展的,因此线程请求分配内存,但堆已满,且内存无法扩展 就会抛出OutOfMemoryError。
java虚拟机规范中定义方法区是堆的一个逻辑部分。其中存放的是虚拟机加载过类的信息,常量,静态变量,即时编译器编译后的代码。 特点: 1》 线程共享
方法区是堆的一个逻辑部分,因此和堆一样,都是线程共享,整个虚拟机中只有一个方法区。
2》永久代
方法区中的信息一般需要长期存在,而且他是堆的逻辑分区,因此用堆的划分方法,把方法区称为老年代。
3》回收效率低
方法区中的信息一般都是长期存在的,回收一遍内存后可能只有少量的信息无效。 对方法区的内存回收主要目标:常量池回收和类型卸载。
4》Java虚拟机规范中对堆的要求比较宽松,允许扩展,也可固定,还允许不进行垃圾回收。
方法区中存放三种数据:类信息,常量,静态变量,即时编译器编译后产生的代码。常量存放在运行时常量池中。
一搬在一个类中通过 public static final来声明一个常量,当这个类被加载,class文件中的常量就存在于运行时常量池。 运行期间也可以象常量池中加新的常量。如String类中的intern()方法。
当运行时常量池中的某些常量没有被对象所引用,同时也没有被变量引用,此时就会进行垃圾回收。
直接内存是出Java虚拟机之外的内存,但是也有可能被Java使用。
在NIO中引入了一种基于通道和缓冲的IO方式。它可以调用本地方法直接分配Java虚拟机之外的内存,然后通过一个存储在Java堆中的DirectByteBuffer对象直接操作该内存,而无需将外面内存中的数据复制到堆中在操作,从而提升的数据操作的效率。
直接内存的大小不受Java虚拟机控制,但是当内存不足时就会抛出OOM异常。
从永生代到元空间,从小范围自动扩展到永生代避免溢出。
不同对象的生命周期不同。把不同生命周期的对象放在不同代上,然后采用最合适的方法回收。
年轻代:存放新生成的得对象。
年老代:在年轻代中经历了N次垃圾回收依然存活的对象,放到年老代。
持久代:用于存放静态文件,如java类,方法等。
新生代的垃圾回收器名为**“minor gc”** 老年代的垃圾回收器:“Full Gc或者Major GC”。 当我们调用System.gc()强制执行的是Full Gc。
1》引用计数:当对象的引用数为0的时候,便可进行回收。
2》对象引用遍历(线性可达性分析) 如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。 在遍历阶段,gc必须记住那些对象可达,以便删除不可达对象,这就叫做标记对象
1》 GC在优先级最低的线程中运行,一般在应用程序空闲即没有线程运行时被调用。
2》Java堆内存不足时,GC调用。
对象现在新生代中分配,若没有足够空间,Minor GC;
大对象(需要大量连续的内存空间)直接进入老年态,长期存活的对象进入老年态。如果对象在新生代出生并经过一次Minor GC 后依然存活,年龄加1,当年龄超过一定限制后(15),则进入老年态。
串行收集器: 暂停所有应用的线程来工作, 单线程。
并行收集器:默认的垃圾回收器。暂停所有应用;多线程。
G1收集器:用于大堆内存。堆内存分隔,并发回收。
CMS是收集器:多线程扫描,标记需要回收的实例,清除。
ClassLoader():将java类加载到虚拟机中,java源程序经过编译器编译之后转化为java字节码文件(.class),类加载器负责将java字节码文件加载到java.lang.class类的一个实例。
**双亲委派机制:**某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成加载任务,返回成功,否则,才会自己去加载。
java内存模型的主要目标:定义变量的访问规则。
java线程之间的通信有java内存模型(JMM模型)来控制。 所有的变量都存在主内存中,每个线程都有自己的工作内存,线程的工作内存中保存了被改线程使用到的变量的主内存副本拷贝,线程对所有的变量操作堵在自己的工作内存中完成,不能直接读取主内存中的变量。不同的线程无法直接访问对方的工作内存,线程间变量的传递需要通过主内存来完成。 线程间的通信: 1》首先,线程A,把线程A中已经更新过的共享变量刷新到主内存中。 2》然后,线程B到主内存中去读取线程A刷新的变量。
前提:必须知道要通信的Java项目(接收请求方)的服务器的IP地址和访问路径。
Http请求: 1 使用Apache的httpClient 2 使用JDK自带的java.net包下的HttpURL Connection方式。 传递有两种方式:POST(一般用于请求消息实体)和GET(请求一般跟在url之后)方式,使用setRequestMethod()方法设置传递方式。
指令重排序:编译器或运行时为了优化程序性能而采取的对指令重新排序的一种方式。
单线程模式下:对存在控制依赖的指令重排序,不会影响执行结果。
多线程模式下:对存在控制依赖的指令重排序,会影响执行结果。
OOM错误:直接内存不足,溢出。
stackoverflow错误:可能是程序无先递归引起的。请求深度超过了当前所允许的最大深度
permgen space: 永久区域不足,解决办法如下: 手动设置MaxPermSize大小,如果是linux系统,修改TOMCAT_HOME/bin/catalina.sh,如果是windows系统,修改TOMCAT_HOME/bin/catalina.bat, CATALINA_OPTS=" -Djava.library.path=/usr/local/apr/lib -server -Xms1024M -Xmx2048M -Xmn256M -XX:PermSize=256M -XX:MaxPermSize=256M"
主要参数:堆大小设置,垃圾回收器选择,内存大小。
目录结构
/bin:存放windows或linux平台上关闭和开启Tomcat的脚本。 /conf:存放tomcat服务器的各种全局配置文件,其中有web.xml和server.xml /dos:存放Tomcat文档 /server: 包含三个子目录:classes lib webapps /serverlib:存放Tomcat所需的各种JAR文件 /ser/webapps:存放Tomcat自带的两个web应用admin和manager应用 /common/lib:存放tomcat服务器以及所有web应用可以访问的jar文件 /shared/lib:存放所有web应用度可以访问的文件(不能被Tomcat服务器访问) /logs:执行的日志文件 /src:存放Tomcat的源代码 /webapps:Tomcat的主要发布目录默认情况下将wen应用文件放于此目录 /work:存发过JSP编译后产生的class文件。类加载模式:双亲委派加载模式
**G1收集器:**面向服务端应用的垃圾回收器。过程如下: 初始标记——并发标记——最终标记——筛选回收。整体上看是:标记-整理,局部上看是:复制,不产生内存碎片。
CMS收集器: 以获取最短停顿时间为目标的收集器,基于“标记-清除”算法实现,过程如下: 初始标记——并发标记——重新标记——并发清除。
**吞吐量优先的并行收集器:**达到一定吞吐量为目的,适用于科学技术和后台处理
响应时间优先的并发收集器: 保证系统响应时间减少垃圾收集时的停顿时间。适用于服务器,电信领域等
1》保证此线程对所有变量的可见性。
2》禁止指令重排序
Volatile修饰的变量不一定是线程安全的,如非原子操作:c++
强引用:new出的对象之类的引用,强引用在就用永远不会被回收。 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。
软引用:用来描述一些有用但并不是必须的对象(常用于网页缓存)。只有在内存不足时JVM才会回收该对象。
import java.lang.ref.SoftReference; public class SoftRef { public static void main(String[] args){ System.out.println("start"); Obj obj = new Obj(); SoftRefere<Obj> sr = new SoftRefer<Obj>(obj); obj = null; System.out.println(sr.get()); System.out.println("end"); } } class Obj{ int[] obj ; public Obj(){ obj = new int[1000]; } } **优点:加快内存回收速度,防止内存泄漏。**弱引用: 非必须对象,能生存到下一次垃圾收集发生之前。
**虚引用:**对生存无影响,任何时候的可以被回收
设计思路:用一个HashMap来保存图片路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会主动回收这些缓存图片对象所占用的空间,从而避免了OOM的问题。
classpath是javac编译器的一个环境变量。他的作用与import,pachage 有关。 package的所在位置,就是设置classpath,当编译器面对import,package时 他会先查找CLASSPATH所指定的目录,并检查子目录java/util是否存在, 然后找出名称吻合的已编译文件。如果没有找到就会报错。
动态加载它。