0%

文章字数:1046,阅读全文大约需要4分钟

GC要关注的事情

  • where/which
  • When
  • How

垃圾回收器组合

垃圾回收器组合

  • 新生代的垃圾回收器几乎都是复制法,90%对象朝生夕死(minor gc)Eden区
  1. Serial新生代,复制算法,单线程,简单高效,适合内存不大的情况
  2. ParNew新生代,并行多线程,Serial的多线程版本,搭配CMS的首选
  3. Parallel Scavenge新生代,吞吐优先,类似ParNewServer级别多核机器默认方式,适用后台运算不需要太多交换的任务

吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
垃圾收集时间=垃圾回收频率*单词回收时间

  • 老年代
  1. Serial Old标记整理,单线程,Client模式默认
  2. Parallel Old标记整理,并行,配合Parallel Scavenge面向吞吐量的组合,使用吞吐量注重和cpu资源敏感场合
  3. CMS老年代,标记清除,并行和并发。尽可能缩短垃圾收集器时间占用,但是占用更多cpu以及内存碎片,浮动垃圾问题,注重服务器相应的场合,互联网后端主流
  4. G1新生代+老年代,并行并发,1.7后引入,采用分区回收,基本不牺牲吞吐量的前提下完成低停顿回收,可预测停顿。目标是取代CMS(采用分块,总体是标记整理,分区间是复制)

java -XX: +PrintCommandLineFlage -version查看jdk默认信息

指定垃圾回收器

-XX:+UseSerialGC新生代和老年代都是穿行收集器
-XX:+UseParNewGC新生代ParNew老年代Serial Old(关注停顿时间,适合用户交互)
-XX:+UseParallelGC新生代ParallerGC老年代Serial Old(吞吐量,关注用户代码执行的总比例)
-XX:UseConcMarkSweepGC新生代ParNew老年代CMS
-XX:+UseG1GC使用G1

其他

UseParallelGC的参数
-XX:MaxGCPauseMills最大停顿时间
-XX:GCTimeRatio吞吐量的倒数,即GC占用时间占用总时间的比例

ZGC

jdk11提供,的可拓展低延迟收集器

  • TB级别的堆
  • GC时间不超过10ms
  • 和G1相比,吞吐量降低不超过15%
  • 有色指针和内存屏障

G1

  • 垃圾优先,优先清理垃圾多的区域
  • 并行并发,分代收集。空间整合,整体是标记-整理,区域间是复制算法。没有空间碎片,可预测的停顿。
  • 初始标记,短暂停顿,仅仅标记一些GC Roots能直达的对象,速度很快
  • 根区域扫描,从新生代可以直接到达的老年代区域
  • -XX:MaxGCPauseMillis指定目标最大停顿时间,G1尝试调整新生代和老年代比例,堆大小,晋升年龄
  • -XX:ParallerGCThreadsGC工作线程数量

内存回收和分配策略

  • 对象优先进Eden区,Eden内存不足发生Minor GC
  • 大对象直接进老年代,大字符串和大的数组
  • -XX:PretenureSizeThreshreshold指定大于这个值直接进入老年代(默认0,即大对象不直接进入老年代)
  • 存活对象默认15岁进入老年代
  • -XX:MaxTenuringThreshold指定进入老年代的年龄
  • 空间分配担保,survivor空间不够,只要老年代连续空间大于新生代对象的总大小或历次晋升平均大小,进行Minor GC否则Full GC

新生代配置

  • 新生代分为Eden区(80%)和survivor区(20%分为s1s2)
  • 新对象存放在Eden,上次存活的放在s1或s2中,gc时向s1或s2中转移
  • -XX:NewSize/MaxSize高优先级
  • -Xmn(NewSize=MaxNewSize)中
  • -XX:NewRatio比例,低

jdk工具

  • jps列出当前电脑运行的进程id -q只要id -m传入main的参数 -l列出临时文件 -v列出虚拟机启动的显示参数
  • jstat虚拟机统计信息监控 -gc id time i每time毫秒打印一次gc信息,共i次
  • jinfojava配置信息工具
  • jmap内存映射
  • jstack堆栈跟踪
  • jConsole监控管理
  • VisualVM多合一故障处理

文章字数:234,阅读全文大约需要1分钟

HQLHibernate Query Language的缩写,提供更加丰富灵活、强大的查询能力,接近SQL语句。

和SQL的区别

  1. HQL:
  • 对查询对象进行了面向对象的封装。from 类名+类对象 where 对象属性
  • 区分大小写,关键字不区分大小写
  • 占位符下标从0开始计算(hibernate5 后不支持)
  • 支持命名参数
  1. SQL
  • 面向数据库表查询。from 表名 where 表中字段
  • 不区分大小写
  • 从1开始计算位置
  • 不支持:命名参数

查询返回结果

  1. 单个对象
  2. 多个
  • object[]
  • list
  1. Map

使用例子

1
2
3
4
5
6
7
public void test(){
Query query = session.createQuery("select new map(b.bookId, b.bookName) from Book b");
List<Map> list = query.list();
for(Map b : list){
System.out.println(b);
}
}
  1. 返回String

    1
    select b.bookName from book b
  2. 返回Object

    1
    select b.bookId,b.bookName from Book b
  3. 返回对象

    1
    select new Book(b.bookId, b.bookName) from Book b
  4. 返回Map

    1
    select new map(b.bookId,b.bookName) from Book b

占位符

1
2
3
Query query = session.createQuery("from Book where bookId in (:bookIds)");
query.setParameterList("bookIds", new Integer[] {1,2,3});
List list= query.list();

hibernate5之后

1
2
Query query = session.createQuery("from Book where bookId in (:bookIds)");
List list = query.setList("bookIds", xxxx).list();

连接查询

1
select o.orderNo,oi.quantity from Order o, OderItem oi where o = oi.order

函数

  • sun总共
  • avg平均
  • max最大
  • min最小
  • count总共

分页

1
2
3
4
Query query = session.createQuery("from Book");
query.setFirstResult(2);
query.setMaxResults(3);
List<Book> list = query.list();

文章字数:1111,阅读全文大约需要4分钟

GCGarbage Collection)垃圾回收机制,对死亡的对象侵占的空间释放。

垃圾回收场所

JVM的垃圾回收主要在堆,其次是方法区。

具体实现

  1. 分区
    JVM将堆内存分成三部分
  • 新生代(Young Generation)
    新生代分为伊甸园Eden Region幸存者区Survivor Region
    幸存者区又分为Form Survivor RegionTo Survivor Region
    幸存者区的两个部分是from还是to并不固定,有对象的就是from另一个是to
    所以新生代总共是三部分,协同工作。
  • 老年代(Old Generation)
  • 永久代(Perm Generation)
    java8后变成元数据区
  1. 回收条件
  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
  • 加载该类的ClassLoader已经被回收
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
  1. 回收过程

新生代

  • 新对象首先进入Eden
  • 再来一个对象,加入Eden区剩余内存不够。此时会触发一次Minor GC,把Eden区存活的对象转移到From
  • 给新对象分配内存,放到Eden

老年代

  • 在进行Minor GC时发现,存活的对象在To区中存不下,那么把存活的对象存入老年代
  • 大对象直接进入老年代:若新创建的对象很大,即使Eden区有足够的空间,也不会放在Eden区,而是直接存入老年代。(PretenureSizeThreshold设置,默认3M)
  • 长期存活的对象将进入老年代:如果对象在Eden出生且经过1次Minor GC后仍存活,并能被To区容纳,将被移动到To区,并把对象年龄设置为1,对象过1次Minor GC,年龄就+1,当它的年龄增加到一定程度(默认15岁,配置参数-XX:MaxTenuringThreshold),就会被晋升到老年代中。
  • 动态对象年龄判定:如果在From中,相同年龄所有对象的大小总和大于From和To空间总和的一半,那么年龄大于等于该年龄的对象就会被移动到老年代,而不用等到15岁(默认)
  1. GC运行方式

  2. 串行GC:client模式下默认GC方式,使用-XX:+UseSerialGC指定

  3. 并行GC:server模式下默认GC方式,可用-XX:+UseParallelGC指定

  4. 并发GC:CMS GC时默认采用,可用-XX:+UseParNewGC,-XX:+UseConcMarkSweepGC指定;

吞吐量收集器使用并行版本的新生代垃圾收集器,用于中大规模数据的应用程序。
串行收集器对大多数的小应用(在处理器上需要大概100M左右的内存)就足够了。

  1. 存活判断
  • 引用计数算法
    给对象添加一个引用计数器,当有地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;计数器为0的对象就是不被使用的。

  • 可达性分析算法
    通过GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

  1. 垃圾清除算法
  • 标记-清楚算法(Mark-Sweep)
    用在老生代中, 先对对象进行标记,然后清除。标记过程就是第五部分提到的标记过程。值得注意的是,使用该算法清楚过后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

  • 复制算法(Copying)
    用在新生代中,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另外一块上,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。
    (内存缩小,代价太高)


文章字数:273,阅读全文大约需要1分钟

HashMap初始大小为16,即内部容器容量为16。但是如果是自定义大小的HashMap,那么什么情况下会触发扩容?

关键点

  1. loadFactor:负载因子,默认0.75f。当内部元素大于容器容量*负载因子时触发扩容。

  2. table:实际存储数据的数组transient Node<K,V>[] table;初始化大小也就是table的大小。

  3. tableSizeFor():这个方法保证传入的初始化值是2 的 N 次幂,比如传入1000,经过这个方法转换就成了1024。而实际存储大小为768(1024 * 0.75)

扩容机制

  1. 传入的初始大小经过tableSizeFor()转换,保证值为2 的 N 次幂
  2. 初始化负载因子为0.75f
  3. 生成内部存储数组table,大小为初始化传入的值,默认16
  4. 当内部元素超过扩容阈值(初始化大小*负载因子)时扩容,扩容大小为原理的一倍

建议

初始值 = (需要存储的元素 / 负载因子) + 1


文章字数:177,阅读全文大约需要1分钟

  1. 内部使用transient Node<K,V>[] table;存储数据

  2. 插入和读取元素主要通过hash算法将key转换成相应数组下标。当多个元素拥有同一个hash值时这些元素就会在这个数组下形成链表,(jdk1.8)之后链表元素超过8个就会使用红黑树的形式存储。

  3. 插入之前会判断一下是否需要扩容,扩容机制另一篇文章有说明。HashMap扩容机制

  4. 序列化时table字段不会被保存因为被transient修饰。HashMap重写了writeObjectreadObject方法,以保证系列化时数据的保存。


文章字数:101,阅读全文大约需要1分钟

HttpServletRequestWrapper使用了装饰模式可以增强request

包装

1
request=new RequestWrapper((HttpServletRequest)request);

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
class RequestWrapper extends HttpServletRequestWrapper{
//重写需要修改的方法
@Override
public String getParameter(String name) {
return filter(super.getRequest().getParameter("name"));
}

//过滤...
private String filter(String value){
//...
return value;
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@WebFilter(filterName = "xssFilter", urlPatterns = { "/*" })
public class XSSFilterimplements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

// 对request和response进行一些预处理
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 包装一下request
chain.doFilter(new RequestWrapper((HttpServletRequest)request), response); // 让目标资源执行,放行
}

@Override
public void destroy() {}
}

文章字数:703,阅读全文大约需要2分钟

Http请求头中有一些可以控制安全策略的部分,通过设置这些头可以提高网站安全系数

X-Frame-Options/Frame-Options

如果网站可以嵌入到IFRAME元素中,则攻击者可以建一个假网页,在假网页中嵌套真实的网站。即使有跨站点请求伪造保护,这种攻击也是可能的,并且被称为clickjacking
创建X-Frame-Options标题可以允许网站所有者决定哪些网站允许构建(嵌套)。
通常设置成

  1. SAMEORIGIN: 允许同源策略的资源嵌套
  2. DENY: 拒绝任何资源嵌套

X-Frame-Options 标题已被弃用,将由内容安全策略中的Frame-Options指令替换,该指令仍处于活动开发阶段。但是,“X-Frame-Options”标题目前具有更广泛的支持,因此仍应实施安全措施。

Content-Security-Policy

内容安全策略(CSP)旨在web程序通知浏览器有关应用程序预期行为(内容源、脚本源、插件类型、和其它远程资源),即设置引入的图像、脚本等资源的限制。可以防止跨站脚本攻击等。

例:CSP指定您的网站希望从任何URI加载图像,从受信任的媒体提供商(包括内容分发网络)列表中插入插件内容,以及仅从您控制的服务器加载脚本

1
Content-Security-Policy:default-src'self'; img-src *; object-src media1.example.com media2.example.com * .cdn.example.com; script-src trustedscripts.example.com
  • none不匹配任何东西
  • self匹配当前域,单不包括子域。例如xxx.com可以,www.xxx.com不行
  • unsafe-inline允许内嵌脚本样式
  • unsafe-eval允许通过字符串动态创建脚本,如evalsetTimeout

X-Content-Type-Options

如果服务器响应头X-Content-Type-Options: nosniffscriptstyleSheet元素会拒绝错误的MIME类型的响应,防止MIME类型的混淆的工具。
如果设置了X-Content-Type-Options: nosniff参数,scriptstyleSheet标签就会过滤非指定的文件类型。正确的MIME应该是text/javascript这样的。

X-XSS-Protection

xss自动过滤的配置,浏览器可以帮助防止跨站点脚本攻击(IE, Chrome, Safari支持)
推荐设置(开启xss防护,并且阻止而不是过滤用户注入的脚本)

1
X-XSS-Protection:1; mode = block。

其它参数

1
2
3
4
0 – 关闭对浏览器的xss防护 
1 – 开启xss防护
1; mode=block – 开启xss防护并通知浏览器阻止而不是过滤用户注入的脚本。
1; report=http://site.com/report – 这个只有chrome和webkit内核的浏览器支持,这种模式告诉浏览器当发现疑似xss攻击的时候就将这部分数据post到指定地址。

X-XSS-Protection标题已被弃用,被内容安全策略的Reflected-XSS指令取代,但是该指令仍处于活动开发阶段。X-XSS-Protection有更广泛的支持


文章字数:55,阅读全文大约需要1分钟
直接比较==对比的是类的地址,equals才是对比值。但是equals对比似乎会有bug,最好使用ob.intValue()转换成int再比较,或者float(ob)转成其他类型比较


文章字数:28,阅读全文大约需要1分钟

Error running ‘ServiceStarter’: Command line is too long. Shorten command line for ServiceStarter or also for Application default configuration.

命令太长

解决方法

.idea\workspace.xml,找到标签 <component name="PropertiesComponent">, 在标签里加一行<property name="dynamic.classpath" value="true" />


文章字数:340,阅读全文大约需要1分钟

JDK动态代理

  • 只能代理接口
  • 思路是新建一个接口的实现类,并持有需要被代理的实现类。将被代理的对象方法进行增强。
  1. 定义一个接口

    1
    2
    3
    4
    public interface Animal {
    String run();
    String jump();
    }
  2. 需要代理的类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Dog implements Animal {
@Override
public String run(){
System.out.println("Dog Running...");
return "ok";
}

@Override
public String jump() {
System.out.println("Dog Jumping...");
return "ok";
}
}
  1. 代理类,需要以Proxy结尾
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class DogProxy implements InvocationHandler {
    // 目标类,也就是被代理对象
    private Object target;

    public void setTarget(Object target)
    {
    this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("前置动作");
    Object result = method.invoke(target, args);
    System.out.println("后置动作");
    }

    // 生成代理类
    public Object CreatProxyedObj()
    {
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    }

CGLIB

  • 可以代理普通类
  • 思路是新建一个子类继承需要被代理的目标类,通过继承的方式持有原来的方法
  • 通过字节码操作形成新的类,会占用方法区(元空间)的空间,过于频繁的操作肯能会导致内存溢出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CglibProxy implements MethodInterceptor
{
// 根据一个类型产生代理类,可以放在其他地方
public Object CreatProxyedObj(Class<?> clazz)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}

@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
{
System.out.println("前置操作");
return arg3.invokeSuper(arg0, arg2);
}
}