
java
文章平均质量分 66
shuxiaohua
这个作者很懒,什么都没留下…
展开
-
Java Finalization‘s Memory-Retention Issues 及Reference类解析
Effective Java Programming Language Guide》 一书中强烈建议不要使用java的finalize()方法去做对象消亡前的清理。因为jvm调用finalize()方法的时机并不确定,容易导致Memory-Retention Issues。通俗点讲就是内存没办法及时回收。详细的见oracle的官方说明https://www.oracle.com/technical-resources/articles/javase/finalization.html。原创 2023-11-22 00:53:40 · 295 阅读 · 0 评论 -
java正则表达式反向字符集避坑
系统导出功能会将自己的信息导出到excel中,为了防止CSV注入攻击,在录入这些字段时需要对内容做校验。CSV注入攻击主要是通过“+、-、@、=”构造一些特殊内容,这个内容导出到excel中,当有人打开这种带攻击的excel时,就可以执行任意命令,详细的攻击方法,大家可以搜索“CSV注入攻击”。原创 2023-03-04 12:13:57 · 290 阅读 · 0 评论 -
POI处理大excel
POI常规的api(Workbook、Sheet等)在处理excel时,会将整个excel的内容加载到内存,碰到大excel时容易OOM。这里“大”并不是单纯的指文件size,一是因为excel是经过压缩,虽然size不大,但是实际内存可能很多;二是excel实际上是使用XML描述的,XML完整的加载到内存,映射成对象时,除了字段的值占内存外,字段本身(指针)也占内存(参考容纳同样的信息,Map比Vo占内存),有些excel比较复杂,会包含大量的元数据,也会造成excel加载到内存后,占用空间较大。基于上翻译 2022-12-06 20:18:38 · 678 阅读 · 0 评论 -
linux系统优化措施汇总-持续更新
当系统物理内存吃紧时,Linux会将内存中不常访问的数据保存到swap上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问swap上存储的内容时,再将swap上的数据加载到内存中,这就是我们常说的swap out和swap in。原创 2022-11-12 11:25:32 · 431 阅读 · 0 评论 -
request.getRequestDispatcher().forward()的妙用以及DispatcherType 对Filter配置的影响
背景我们应用如上图所示,Nignx做负债均衡,微服务间使用feign进行调用。为了方便鉴权Filter配置拦截的url以及nginx配置对外暴露的url,我们为所有服务设计了统一的url规范类型用途v1/xx给前端用的urlv5/xx内部接口,服务间调用因此所有服务都未配置server.servlet.context-path那么问题来了,现在我们要把服务从虚拟机迁移到docker中。使用公司的docker需要有用于分发的文根,因为docker服务提供了公共域名原创 2022-04-22 20:32:35 · 3366 阅读 · 0 评论 -
java.lang.OutOfMemoryError: Java heap space的思考
背景excel文件内容较多时,使用poi非流式api处理,很容易造成OOM;OOM后系统日志发现大量报错ERROR org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled taskjava.lang.IllegalStateException: Connection pool shut down at org.apache.http.ut原创 2022-03-09 20:47:58 · 1370 阅读 · 0 评论 -
连接池剖析及连接泄漏定位思路
背景最近连续解决两起连接泄漏的问题,期间阅读了大量开源源码,发现开源软件中设计的连接池,用的也都是一些常规手段,本文为大家揭开这层神秘的面纱。概述大多数应用中应该都是用的TCP协议,TCP连接在建立阶段会经过3次握手,销毁阶段会经过4次握手。标准网络是分7层的,每一层都有各自的协议头,应用层拿到的有效数据,在整个报文中占比没这么大。TCP握手阶段的报文,对应用层来讲都是额外的负担。所以很多客户端都会设计连接池,来复用已建立的连接。减少创建连接带来的消耗。连接池本身不复杂,如果不想做的通用,少量的代码原创 2022-01-12 11:56:05 · 1611 阅读 · 2 评论 -
YYYY-MM-dd时间格式跨年的bug
今天系统出现查询数据失败的问题,查询日志发现查询条件中,时间错误。今天是2021年12月27日,但是日志中的时间却变成了2022-12-27 18:16:05,414。然后查询JDK源码的注释发现,“yyyy-MM-dd HH:mm:ss”中大小写代表不同的含义,以前写oracle时间转换的时候,oracle是忽略大小写的,没想到经验带到java里面翻了车。大家可以去查看SimpleDateFormat这个类的源码,里面对每个字母简写的意义做了说明。尤其是对于“年”,有如下注释y表示正常的年Y原创 2021-12-27 18:37:31 · 1080 阅读 · 1 评论 -
java反射高阶用法
获取泛型上注解hibernate validator可以对容器的元素进行校验,比如List<@length(max = 50) String>。很好奇校验器是如何获取到@length这个注解,并对容器里面的元素进行校验的。通过google发现可以通过如下方式获取。详细见https://stackoverflow.com/questions/66241813/how-to-parse-java-annotation-in-generic-typeclass Test { L原创 2021-11-20 18:07:45 · 321 阅读 · 0 评论 -
给类字段、方法动态添加注解
背景我们系统是业务中台,经常会调用第三方系统,部分接口还是直接透传。为了提高开发效率,开发了类似feign的组件。feign主要原理是扫描@FeignClient的接口,然后使用代理生成类实例。(我们系统调用后端时鉴权方式很多,而且参数传递方式也比较复杂,因此自己开发了一个类似的组件)目前存在一个问题,就是有些接口我们属于透传,但鉴权在我们这里;项目的框架使用权限注解,通过切面统一处理鉴权逻辑。权限注解在接口上,动态生成的代理类上面没有注解,因此spring的切面不会对其进行拦截。因此google原创 2021-08-02 20:35:54 · 8048 阅读 · 18 评论 -
apache HttpClient参数说明
正文HttpClient组件使用的地方较多,很多HTTP客户端都是封装的HTTPClient(spring restTempalte就是基于HTTPClient构建的);HTTPClient可以设置的参数较多,部分参数的设置堆系统影响较大,需要对各个参数有个透彻的了解。以下是基于使用PoolingHttpClientConnectionManager项目说明默认值备注maxConnTotalHTTPClient能够创建的最大连接数20达到上线后,需要等待其他连接销毁后才能原创 2021-07-04 18:18:32 · 2868 阅读 · 0 评论 -
java SSLContext创建
概述HTTPS相对于HTTP多了SSL(security sock layer),应用层将数据丢给TCP时,需要经过SSL层的加密处理;TCP层的数据丢给应用层时,需要经过SSL层的解密处理。因此网络中传输的都是加密后的数据,提高的通信的安全性。HTTPS除了拥有传输加密的功能,还提供身份认证,防止对端伪造身份。这个是通过HTTPS证书实现。注下图中对HTTPS握手过程进行简化,握手过程的关键步骤就是证书校验及对称加密秘钥的协商,另外客户端证书的校验是可选的。问题标准证书都是第三方机构颁发原创 2021-07-04 16:39:37 · 10084 阅读 · 1 评论 -
ThreadLocal的内存泄露?
ThreadLocal设计的目的按照jdk源码的注释,ThreadLocal用于保存线程本地变量。区别于普通变量时所有线程共享的,ThreadLocal保存的变量原创 2021-06-04 23:51:10 · 128 阅读 · 1 评论 -
记一次json序列化采坑
背景本项目组与其他项目组通过restful接口进行集成,后台返回的数据中有个字段叫rList.使用spring的resttemplate集成时,该字段的值始终无法设置进去。定位过程及思路确认返回结果是否与本项目组定义的类型匹配经排查项目组定义的数据类型对比后端返回的结果,我们这边有部分字段缺失, --我们并不需要后端所有的字段猜测,因为后端有些字段没在vo中定义,导致反序列化调用失败排查手段经检查部分字段有成功设值,所以应该没有序列化失败,肯定有某种原因导致rList这个字段反序原创 2021-05-28 21:51:55 · 553 阅读 · 0 评论 -
java8 线程池解析
线程池的作用虽然相对进程而言,线程创建的开销要小一点,但是绝对来讲线程的创建开销也不小。线程的创建(start函数执行后才是真正的去创建线程)不仅会进行系统调用,涉及到上下文切换(由用户态切换到内核态)。实际上内核在创建线程时,会涉及到诸多操作,比如分配线程描述符,内存表等。如果线程不进行池化复用,每次都是创建线程,任务处理完后就销毁线程,会极大的浪费创建线程的时间开销。因为如果线程池化服用后,创建线程的开销,会摊薄到每一个任务上面。即使线程池没有任务处理,线程会阻塞在锁上面,不会被操作系统调度,顶多原创 2021-05-26 22:58:08 · 372 阅读 · 0 评论 -
java fail-fast机制
概述fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。该机制设计的初衷在遍历集合元素的过程中,是不希望集合被修改的;不然会产生许多问题,比如:arraylist在遍历的过程中,原创 2020-11-27 16:32:05 · 162 阅读 · 2 评论 -
java 线程状态
概述 public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }State为java线程状态的枚举类,定义在Thread中。java的线程状态是jvm自己定义的,跟操作系统中的线程(或者说原生线程库,比如linux中的pthread)状态没有直接联系,不能相互对应。各状态说明NEWT原创 2020-11-27 11:13:46 · 101 阅读 · 0 评论 -
Annotation中annotationType和getclass的区别
概述JDK中获取注解时,返回的都是Annotation类型,如下(截取自JDK源码) public <A extends Annotation> A getAnnotation(Class<A> annotationClass)当获取到Annotation的实例后,可以通过getClass(从Object继承而来)和annotationType(Annotation接口中的方法)获取到相关的Class。下面阐述一下两者的区别,以下内容为自己的推断,并不是通过翻阅源码获得原创 2020-11-17 10:30:38 · 3510 阅读 · 1 评论 -
java @inherited注解
概述名字解释:继承注解,被@inherited标识的注解,比如@inheritedpublic @interface A {…};A就是一个继承注解@inherited是元注解中的一种,只能应用于对类的注解。如果一个类具有继承注解,那么他所有的子类也拥有该注解解释:@inherited并不是让注解继承注解,而是子类可以继承父类上面用@inherited标识过的注解无法直接获取注解上的注解,即使加了@inherited// 为了简洁,其他无关的注解未写出来,比如(@Retention(Re原创 2020-11-16 19:27:25 · 566 阅读 · 0 评论 -
java编程中的一些小技巧(一)
大于给定的数,且是2的N次方,最小值使用背景集合类一般都会分配数组来存储元素,数量都是2的N次方;当需要扩容时,就计算比当前数量大且是2的N次方的最小值,作为扩容后的容量代码public static int findNextPositivePowerOfTwo(final int value) { return 1 << (32 - Integer.numberOfLeadingZeros(value - 1)); }...原创 2020-10-28 11:55:03 · 180 阅读 · 0 评论 -
java内部类访问局部变量为什么要加final
概要java内部类访问局部变量需要加final这是一个设计问题,并不是一个技术问题。jdk1.8里面,对局部变量赋初值后不再修改,不需要加final。虽然看起来语法变了,实际上这是个语法糖,因为赋初值后,不再修改,符合final的特征,所以编译器不强制在定义的时候加final。为什么需要加final内部类的生命周期可能比局部变量长,或者说内部类的方法在真正访问局部变量时,上下文已经变了。比如下面这段代码,匿名内部类真正访问a,b两个变量时,已经不在test这个方法上下文里面了。public cl原创 2020-06-05 11:10:39 · 697 阅读 · 2 评论 -
java 堆外内存
堆外内存和堆内内存堆内内存java堆内内存,是java虚拟机通过malloc分配后,完全自己管理的,跟操作系统的内存管理没啥区别,java虚拟机有完全的控制权。java虚拟机通过记录相关信息,能够完全掌握内存的使用情况(有那些空间是剩余的,那一块内存是属于那个对象的),因此通过可达性算法,能够识别出那些内存能够被释放掉。java的GC并不是真正的调用free将内存归还给操作系统,而是将该块内存放入到可用内存列表里面,类似于内存池化。类似操作系统的内存管理,操作系统也是使用bitmap记录各个内存页的原创 2020-05-29 12:01:20 · 506 阅读 · 1 评论