记一次 stackoverflowerror 线上排查过程

一.线上 stackOverFlowError

    xxx日,突然收到线上日志关键字频繁告警 classCastException.从字面上的报警来看,仅仅是类型转换异常,查看细则发现其实是 stackOverFlowError.很多同学面试的时候总会被问到有没有遇到过线上stackOverFlowError?有么有遇到栈溢出?具体栈溢出怎么来解决?今天他来了,他带着问题走来了.话不说多,直入正题.具体打印的stackOverFlowError细则如下

二.优先线上问题解决

请原谅我抽象的画风

    temp 方案.首先的线上的稳定性肯定是第一要义,客户可不会等你长篇大论抓包,分析,debug.过了30min还不恢复,资本的大刀就要砍到你身上了.所以我们先想到的是代码回退,镜像回滚解决问题优先.虽然说是临时方案,那这时候我觉得这可能是最重要的最佳方案.毕竟老镜像是不会出任何问题的.

三.继续深入分析

    解决完线上的问题后,先从外层的堆栈打印来看,找到 ClassCastException 这里找到真实的原因,毕竟退下来的不仅仅是坏代码,还有需求迭代的正常需求还是需要继续推上去上线.

3.1 整体的流程梳理

    找到报错第一步:

3.1.1 step1: classCastException

    先表象开始分析

从这里可以看到判断了是否为 Throwable 类型.如果是就进行 Exception 强转.这里就要复习一下了.

StackOverFlowError 继承 Error ,ErrorThrowable 继承而来. Exception 则是另外的分支. 对于 ErrorException 也有通行的原则. Exception 一般是程序中用以来抛出程序异常所使用的且一般是能够通过编码优化来解决的,或是用来 try catch exception 来进行捕获处理的. Error 则是用来表达程序运行期间出现的严重错误,这时候通常是jvm级别的.如常见的OutOfMemoryError,stackOverFlowError.等.通常则是无法通过代码来进行捕获的.

    有了这些基础知识后,再回来这里虽然StackOverFlowErrorException都继承于 Throwable .但这是两个子的实现,没法做到强转.由之得到了 ClassCastException .后面这就是转成了 ClassCastException .这个类则是继承自 Exception .通过 try catch 捕获异常后,得到了正常的日志打印,也就是收到的日志告警. 然后这仅仅是表现.根因还没有找到.

    当然这段代码也需要进行优化.如果得到的是Error的类型就要对应的进行Error的处理而不是仅仅对Throwable都统一强转为Exception
代码优化

 Exception exception = null;f(ar instanceof Error){Error arError=(Error)ar; exception=new Exception (arError);}else if(ar instanceof Exception){exception = (Exception) ar;}

3.1.2 step2:事情远没有结束,到底是哪里出问题 StackOverFlowError

    本质上还是由于StackOverFlowError才得到的如上的 ClassCastException. 回忆下 JVM 的内存布局(如下图)

    能发生 StackOverFlowError 只有在线程私有的 stack(native method stack | virtual method stack) 这里.这里通常发生这个错误的原因是因为方法调度的深度过长了或是线程本身分别的内存太小不足以支持现在的复杂调用.

  • 第一种场景:常见的如递归调用.
  • 第二种场景: jvm 在1.5 之后默认的xss 大小默认为 1m.一般场景下支持1000-2000个深度调用没问题.包括递归.(没试过.数值参考自:深入理解java虚拟机)

3.1.3 找到问题对比代码

    从一般情况下第二种场景不太可能出现.还是回到递归调用引起的.排查代码.花不多少,看代码,通过对比版本之间diff(对比时间稍微有点长).简略如下:

无问题代码

private static void error(Logger logger, String message, Object... arg) {if (isLogOn(LogLevelEnum.ERROR, logger)) {if (arg != null && arg.length > 0 && arg[0] instanceof Throwable) {logger.error(message, arg[0]);} else {logger.error(message, arg);}TRACER_LOGGER.error(message, arg);}}
public static void error(Object... arg) {String message = getMessage("{}", 4, arg);error(getSoaErrorLogger(), message, arg);}public static void error(String message, Object... arg) {message = getMessage(message, 4, arg);error(getSoaErrorLogger(), message, arg);}

代码优化后的代码 有问题版

private static void error(Logger logger,String realMessage, String message, Object... arg) {if (isLogOn(LogLevelEnum.ERROR, logger)) {if (arg != null && arg.length > 0 && arg[0] instanceof Throwable) {logger.error(message, arg[0]);} else {logger.error(message, arg);}TRACER_LOGGER.error(message, arg);}}
public static void error(Object... arg) {String message = getMessage("{}", 4, arg);error(getSoaErrorLogger(), message, arg);}public static void error(String message, Object... arg) {message = getMessage(message, 4, arg);final String realMessage=message;error(getSoaErrorLogger(),realMessage, message, arg);}

代码优化后的代码 完善版

private static void error(Logger logger,String realMessage, String message, Object... arg) {if (isLogOn(LogLevelEnum.ERROR, logger)) {if (arg != null && arg.length > 0 && arg[0] instanceof Throwable) {logger.error(message, arg[0]);} else {logger.error(message, arg);}TRACER_LOGGER.error(message, arg);}}
public static void error(Object... arg) {String message = getMessage("{}", 4, arg);final String realMessage=message;error(getSoaErrorLogger(),realMessage, message, arg);}public static void error(String message, Object... arg) {final String realMessage=message;message = getMessage(message, 4, arg);        error(getSoaErrorLogger(),realMessage, message, arg);}

    咋一看没有任何问题.但是上线后出现第二个方法递归调用自身(但是第二个方法没有变更内容哈).本质上的原因就是因为修改第一个方法增加了入参.但是仅修改了第三个方法,第二个方法没有修改.没有出现编译问题.因为本身第二个方法是一个Object… arg的数组调用.好坑.

四.总结

  • 区别ErrorException.系统最外层建议捕获所有异常,也就是Throwable,但是具体是Error,还是Exception要进行区分处理.
  • 尽量不使用,少使用数组式使用.如String… args.Integer… args .即使要用,也尽量不要用Object… args .避免调用错误.
  • 在做技术优化时,尽可能评估影响,对线上抱有充分的敬畏.慎之又慎.如没有特别的收益,可不上线.上线也要保证每一行改动与本次受影响的代码做到测试
  • 修改代码找到所有find usage ,避免出现错改,漏改.可以利用自带IDE的工具 做到.

赠人玫瑰 手有余香,我是柏修
求关注、求点赞,加个关注不迷路,感谢
点赞是对我最大的鼓励
↓↓↓↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/243756.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络爬虫采集工具

在当今数字化的时代,获取海量数据对于企业、学术界和个人都至关重要。网络爬虫成为一种强大的工具,能够从互联网上抓取并提取所需的信息。本文将专心分享关于网络爬虫采集数据的全面指南,深入探讨其原理、应用场景以及使用过程中可能遇到的挑…

【论文阅读笔记】Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation

1.介绍 Swin-Unet: Unet-like Pure Transformer for Medical Image Segmentation Swin-Unet:用于医学图像分割的类Unet纯Transformer 2022年发表在 Computer Vision – ECCV 2022 Workshops Paper Code 2.摘要 在过去的几年里,卷积神经网络&#xff…

OTA 升级软件推荐,附带MD5,CRC16,CRC32,AES算法工具

说明:推荐 OTA 工具软件,可以通过串口按 OTA 协议发送 bin 文件给 MCU,完成 bootloader 升级app 功能 , 这个软件 附带提供 MD5,CRC16,CRC32,AES 算法工具。 文档持续完善中... 1. OTA界面 2.AES.MD5.CRC界面 3.下载链接: 链接: https://p…

AI创作之旅:探索提示工程的奇妙世界

💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】🤟 基于Web端打造的:👉轻量化工具创作平台💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 在当今信息爆炸的时代,人工智能的发…

k8s的helm

1、在没有helm之前,部署deployment、service、ingress等等 2、helm的作用:通过打包的方式,deployment、service、ingress这些打包在一块,一键部署服务、类似于yum功能 3、helm:官方提供的一种类似于仓库的功能&#…

为什么电脑降价了?

周末,非常意外地用不到3000元买到了一款2023年度发布的华为笔记本I5,16G,500G,基本是主流配置,我非常意外,看了又看,不是什么Hwawii,或者Huuawe。然后也不是二手。为什么呢?因为在ALU和FPU之外&…

Android.mk和Android.bp的区别和转换详解

Android.mk和Android.bp的区别和转换详解 文章目录 Android.mk和Android.bp的区别和转换详解一、前言二、Android.mk和Android.bp的联系三、Android.mk和Android.bp的区别1、语法:2、灵活性:3、版本兼容性:4、向后兼容性:5、编译区…

【C++修行之道】STL(初识pair、vector)

目录 一、pair 1.1pair的定义和结构 1.2pair的嵌套 1.3pair自带排序规则 1.4代码示例 二、vector 2.1vector的定义和特性 2.2vector的初始化 一维初始化: 2.3vector的常用函数 2.4vector排序去重 排序: 去重: 示例: 一、pair …

CmakeList教程

一、CmakeList介绍: cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。它会通过写的语句自动生成一个MakeFile,从而实现高效编译 二、CmakeList的常用指令 1.指定…

iphone5s基带部分电源部分主主电源供电及

时序: 1.,基带电源的供电,基带电源也叫pmu。 首先时序图说电池提供供电,电池是J6接口,视频习惯把接口称之为座子。查U2_RF芯片,发现供电信号为PP_BATT_VCC_CONN,但是没查到跟电池座子有关系,电池座子写的是…

回溯算法篇-01:全排列

力扣46:全排列 题目分析 这道题属于上一篇——“回溯算法解题框架与思路”中的 “元素不重复不可复用” 那一类中的 排列类问题。 我们来回顾一下当时是怎么说的: 排列和组合的区别在于,排列对“顺序”有要求。比如 [1,2] 和 [2,1] 是两个不…

电脑磁盘格式化了怎么恢复里面文件?多个方法任你选

在日常生活中,我们可能会遇到由于误操作、病毒攻击等原因导致电脑磁盘被格式化的情况。一旦发生这种情况,我们可能会失去重要的文件,给工作和生活带来很大的困扰。但是,不必过于担心,本文将为您详细介绍如何在电脑磁盘…

Python 什么是点积注意力机制;点击注意力机制代码实现;Dot-Product Attention代码实战;超详细代码实现点积注意力

1.点积注意力机制简介 点积注意力机制(Dot-Product Attention)是一种常用的注意力机制之一,通常与Seq2Seq模型中的自注意力(Self-Attention)机制一起使用。它用于计算查询(Query)和键&#xff0…

Buildroot显示uboot logo

根据之前的开机现象,uboot部分没有开机logo 1、Makefile配置 查看一下u-boot/tools/Makefile是否都有如下配置 # Enable all the config-independent tools ifneq ($(HOST_TOOLS_ALL),) CONFIG_LCD_LOGO y CONFIG_CMD_LOADS y CONFIG_CMD_NET y CONFIG_XWAY_SW…

一.初识Linux 1-3操作系统概述Linux初识虚拟机介绍

目录 一.初识Linux 1.操作系统概述 计算机组成 硬件: 软件: 操作系统: 操作系统工作流程 操作系统作用 常见的操作系统 PC端: 移动端:(掌上操作系统) 一.初识Linux 2.Linux初识 linu…

分布式websocket即时通信(IM)系统保证消息可靠性【第八期】

b站上面本期视频版本,观看视频食用更佳!点击即可跳转,找不到视频可以直接搜索我 目前叫 呆呆呆呆梦 目前已经写的文章有。并且有对应视频版本。 git项目地址 【IM即时通信系统(企聊聊)】点击可跳转 sprinboot单体项目升级成sprin…

Ubuntu用gparted重新分配空间

ubuntu系统使用过程中安装系统时预先留的空间不够使用怎么办? 这么办! 首先 使用df -h 查看当前空间使用情况 已经分配的空间重新规划 ? 先将已分配的空间中的多余空间分离出来; 假设我想将挂载点/home下的一部分空间分给挂载…

《WebKit 技术内幕》学习之八(1):硬件加速机制

《WebKit 技术内幕》之八(1):硬件加速机制 1 硬件加速基础 1.1 概念 这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页,因为GPU的作用主要是用来绘制3D图形并且性能特别好,这是它的专长所在,它…

matlab模型变量一般说明,标定和显示量,以及产生a2l文件,自动填充a2l地址,并使用标定工具ati进行标定(推荐重要)

注意我是用的是matlab2019b 1,输入标定量,使用constant,用cal函数包裹 2,输出显示量,在划线上标注,然后用display函数包裹, 第一步和第二步完成以后,生产标定量a2l 3,输入…

常规二分查找中遇到的问题

以前我们写二分查找的时候&#xff0c;是这么写的&#xff1a; public static int binarySearch2(int []a,int target){int i0,ja.length-1;while(i<j){int mid(ij)/2;if(a[mid]target){return mid;}else if(a[mid]<target){imid1;}else {jmid-1;}}return -1;} 这么写&…