1572662

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

什么情况下对象会进入老年代:
1、minor gc时候,eden区的存活对象无法在survivor区存下,导致这部分对象进入老年代
2、创建的大对象直接存入老年代(可以通过-XX:PretenureSizeThreshold来设置多大的对象算大对象)
3、存活对象的年龄达到设置的阈值时,对象会进入老年代(可以通过-XX:MaxTenuringThreshold参数来设置年龄阈值)
4、survivor区中的存活对象大于survivor区的50%(50%可以通过-XX:TargetSurvivorRatio参数设置)时,
年龄大于这批对象的年龄的最大值的对象会进入老年代


如何设置对象年龄MaxTenuringThreshold比较合适:
比如系统现状是每隔20秒左右产生一次minor gc,而系统的的方法可能最长运行两分钟,所以正常来说方法结束,
对象就可以通过minor gc被回收,相当于方法运行期间可能会经过6次minor gc,对象的年龄是6,如果对象的年龄是
6还没有被回收,基本可以确定对象是存活时间比较长的对象,可以进入老年代了,以防在年轻代来回复制,浪费效率,
我们可以把年龄阈值再设置的大一点,比如设置为8,也比设置为15要有一定的效率优化

jps:查看java进程,可以看到进程id
jmap: jmap -heap 14460(代表进程id) 查看堆信息,包括可以看到堆的一些配置信息和堆的使用情况
jmap ‐dump:format=b,file=eureka.hprof 14660  到处堆信息到文件,可以用jvisualvm命令工具导入该dump文件分析


Jstack:用jstack加进程id查找死锁,
jinfo:查看正在运行的Java应用程序的扩展参数,如:jinfo -flags 12124
查看java系统参数:
Jstat:jstat命令可以查看堆内存各部分的使用量
jstat的关键作用就是可以查看并计算出一些关键的数据,比如做了多少次minor gc,共耗时多少,能算出每次gc耗时时间,
以及查看多久进行一次minor gc等,再根据一些优化原则进行参数调优
jstat -gc pid 300000 10 ,每隔5分钟进行一次查看,可以看出这10次查看过程中老年代增加了多少,
因此就可以推算出老年代的增长速率,而老年代的大小是已知的,因此就可以推算出多久出发一次fullgc,
而fullgc的时间可以通过fullgc的执行次数和总耗时推算出来,因此就能知道了多久进行一次fullgc,以及每次fullgc的平均停顿时间

小总结:
1)jps 查看java 进程,找到对应的pid
2)jinfo -flags pid 查看堆的设置情况
3)jstat -gc pid 300000 10 查看垃圾回收的频率
4)jmap -heap pid 查看当前内存的使用情况
5)jstack pid 查看死锁的情况


优化思路其实简单来说就是尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年
代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。

导致fullgc的几种情况:
1)老年代已满(所谓已满就是达到了设置的比例值的时候),可能有存活对象频繁进入老年代,也可能是因为survivor区
的动态年龄判断机制(超过survivor区的50%)导致年龄大于等于n的对象进入老年代,对于这种情况可以适当调大年轻代的大小
2)元空间不足触发的fullgc
3)老年代分配担保机制导致的fullgc
如果调大年轻代的大小仍然无法解决,我们可以通过jmap命令看下是什么对象导致的老年代不断被占用
jmap -histo pid 比如是查看到是user对象导致的,但是程序中用到user对象的地方太多,不能定位具体位置,
我们可以同时分析下占用cpu较高的线程,一般有大量对象不断产生,对应的方法代码肯定会被频繁调用,占用cpu必然较高,
可以用jstack或jvisualvm来定位cpu使用较高的代码

 

 

rocketmq:
1)rim开票中台作为消费者:只从mq中指定的topic取数据
2)rim开票中台作为生产者,回写消费的消息成功与否的结果,向mq写数据时,会存在多个topic,一个业务系统对应一个topic,
而一个系统中的不同业务请求可以用不同的tag进行区分
记忆总结:一个消费者业务系统对应一个topic,即topic是根据消费者来定的,
比如:rim作为消费者的时候,相当于别的系统调用rim的接口,所以别的系统发送的topic必须与rim消费时定的topic保持一致;
而rim作为生产者回写处理结果的时候,别的业务系统是消费者,所以回写消息时,会对应多个topic,
然后别的系统读取各自对应的topic中的信息

rim开票中台为nbi非商提供开票申请和开票作废接口,都是通过http的形式进行同步调用,其他的系统的开票申请时调用的汉生系统进行开票,
但是现在汉生系统需要进行下线,因此其他系统的开票申请也改为调用rim的开票接口,考虑到rim的开票接口压力增大,可能会抗不住
压力,因此采用rocketmq进行异步开票,rim作为消费者从mq中指定的topic进行消费,而其他业务系统也是将开票申请发送到同一个topic,
而rim在进行消息消费后,不管成功与否,都需要将处理结果以发送到mq,此时rim作为消息的生产者,而其他业务系统作为消息的消费者,
每个业务系统取不同的topic中的内容进行消费,因此rim就需要在发送消息到mq的时候指定不同的topic,因此需要在rim中的配置表中
配置不同的系统对应的topic,rim根据系统业务系统的系统编码从配置表中取出对应的topic进行消息发送。由于开票接口采用mq的形式
进行异步处理,而作废接口采用同步的形式进行作废,就会引发一个问题:开票申请发送到mq后,rim中台还没有进行消费,在对应的
申请单表中还没有对应的申请数据,而此时业务系统调用了作废接口对申请进行作废,由于申请数据不存在,所以无法作废,因此新增
一张作废申请表保存作废申请的相关数据,当rim消费mq中的开票申请的消息时,不是直接进行开票的相关逻辑,而是需要先判断在
作废申请表中是否存在对应的作废申请数据,如果存在,则需要对申请单进行作废的逻辑处理,并删除作废申请表中对应的数据;如果在
作废申请表中不存在作废请求,才进行相关的开票逻辑。

 

redis的使用:
1)作为分布式锁
2)用作缓存,数据字典存在B系统中,A系统需要从B系统的查询数据字典信息,A系统的接口上可以加上redis缓存,B系统上也
可以加上redis缓存,如果是B系统上加缓存,那么如果B系统的数据字典发生改变的时候可以更新缓存,这是不会有数据不一致的问题的,
但是如果A系统的接口上加了缓存,B系统改了数据字典A是感知不到的,此时A查询到的数据时不准确的,只能等到缓存到达失效时间
以后,才能从新真正调用B系统的接口

 


数据库连接工具:DataGrip
linux服务器连接工具:MobaXterm


reis工作中遇到的问题:
开票申请通过rocketmq进行异步消费,申请作废通过http同步调用接口进行作废,若开票申请单已存在,则进行作废时
可对申请单进行作废逻辑处理;若申请单不存在,则调用作废接口时,需要将作废消息保存到数据库表中,待消费申请
消息时,查询表中是否存在作废请求,若存在,则进行作废处理;总而言之就是如果存在作废请求,最终申请单需要是
作废状态。但是现在由于并发问题,可能存在开票申请和作废申请同时进行的情况,因此需要利用redis加分布式锁,
为了保证锁的粒度较小,申请接口的锁加在了查询作废表以及向申请单表中中插入数据这块,这就导致了一个问题,
就是申请单接口加锁,查询作废表中不存在数据,因此直接向申请单表中插入数据,插入之后释放锁,此时作废接口库
获得分布式锁,理论上应该对申请单进行作废,但是由于申请单接口还存在操作其他表的操作,导致事物没有提交,
这就涉及到mysql的隔离级别了,mysql采用的隔离级别是可重复读,因此,由于事物没有提交,作废接口并不能查询到
申请单表要插入的申请单数据,因此也无法进行作废处理,只是将作废申请保存到表中,
因此就出现了最终表中既保存了未作废的申请单,作废表中又保存了作废数据,这样的结果不是我们要的结果,
我们希望得到的结果是作废表中无需保存作废申请数据,申请单表中保存的是作废的申请单。

posted on 2020-09-17 10:38  1572662  阅读(133)  评论(0)    收藏  举报