<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[DoasIsay的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/DoasIsay</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; DoasIsay]]></copyright><item><title><![CDATA[科普篇之Java堆内缓存优化-重复数据集复用]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/146008698</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/146008698</guid><author>DoasIsay</author><pubDate>Tue, 04 Mar 2025 10:50:39 +0800</pubDate><description><![CDATA[通过观察发现主播在短时间内识别出的ai标签变化并不大，目前线上是保留主播最近120个识别标签集，对于同一个主播有可能120个识别标签集完全一样，而主播与主播间也可能存在相同的识别结果。那么是不是可以从之前的120个识别标识集中找到一个与最新识别相同的标签集的引用，而不是new一个新的标签结果集？如此看来对一些识别结果变化不大的主播则可以大大的减少的内存使用。每个在线主播的ai标签每5s生成一个，包含50多个标签识别集。通过对比垃圾回收后的内存占用，粗略估计减少了近3G的内存使用。还记得主播ai标签的优化？]]></description><category></category></item><item><title><![CDATA[科普篇之Java堆内缓存优化-对象or基本类型]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/146008409</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/146008409</guid><author>DoasIsay</author><pubDate>Tue, 04 Mar 2025 10:41:33 +0800</pubDate><description><![CDATA[﻿由于基本类型本身占用内存比较小此处float是4个字节，而使用一个包装类型做为类成员变量就会多占用24字节，如果当堆内缓存中存在大量的包装类型时，就会额外占用大量内存。如下声明对象，B对象就比A对象多占用24字节，怎么又多了8个字节？因为B.data中存放的只是指向堆内对象的引用又占用了8字节。在我们的场景中使用float替换Float后通过对比垃圾回收后的内存占用，粗略估计减少了近2G的内存使用。在64位下无指针压缩，不考虑内存对齐，对象头8字节+指向类型信息的指针8字节=16字节。]]></description><category></category></item><item><title><![CDATA[科普篇之Java堆内缓存优化-IntegerCache的使用]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/146007686</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/146007686</guid><author>DoasIsay</author><pubDate>Tue, 04 Mar 2025 10:29:02 +0800</pubDate><description><![CDATA[假如在4000个主播正在直播，那么内存中就会存在4000*120*50=24000000，2千多万重复的主播标签id，而标签id在我们系统中要么是String，要么是int，对于String类型的我们可以用String.intern()优化，对于int类型我们可以使用包装类型Integer，利用其IntegerCache进行优化，消除重复的标签id。在我们的场景中使用String.intern()和IntegerCache优化ai标签后通过对比垃圾回收后的内存占用，粗略估计减少了近4G的内存使用。]]></description><category></category></item><item><title><![CDATA[科普篇之Java堆内缓存优化-StringCache的使用]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/146007100</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/146007100</guid><author>DoasIsay</author><pubDate>Tue, 04 Mar 2025 10:15:33 +0800</pubDate><description><![CDATA[在推荐服务内部会缓存很多i2i的相似词表，结构为Map<String,List<String>>，key为主播id，value的List中存放的是与key相似的主播id列表（用途就是比如你看过主播a，就会把与主播a相似的其它主播推荐给你），虽然只有3万量级的主播，但这样一个Map，往往会有1000多万个主播id，其中绝大部分是重复的主播id。在我们的场景中使用String.intern()优化i2i词表后通过对比垃圾回收后的内存占用，粗略估计减少了近6G的内存使用。]]></description><category></category></item><item><title><![CDATA[百无聊赖篇之我与netty的第一次亲密接触-BrpcJava误用之堆外内存泄漏]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/144032523</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/144032523</guid><author>DoasIsay</author><pubDate>Tue, 04 Mar 2025 09:59:24 +0800</pubDate><description><![CDATA[话不多说jstack导出线程栈，不得不说运气是好到爆炸，只有brpc-jave使用的是NIO，如果dubbo，lettuce，brpc-java，使用的都是NIO，或都是EPOLL，那么我们就无法区分，就需要我们手动进行设置，其中一个与其它两个不同，以便确认是那个框架创建的ByteBuf泄漏了。由日志我们知道，泄漏的ByteBuf是netty的EvetLoop线程创建的，接下来我们要确定的是，到底是dubbo，lettuce，brpc-java中的那个框架在使用ByteBuf后没有release。]]></description><category></category></item><item><title><![CDATA[使用arthas进行接口性能测试]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/120215964</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/120215964</guid><author>DoasIsay</author><pubDate>Fri, 10 Sep 2021 10:15:29 +0800</pubDate><description><![CDATA[Arthas 用户文档 — Arthas 3.5.4 文档



下载安装arthas

curl -O https://arthas.aliyun.com/arthas-boot.jar

启动

sudo /data/zgc/jdk-11/bin/java -jar arthas-boot.jar

选择需要attach的进程，输入1





此次修改了recommend.algoframe.recaller.BaseNewCFSimi类的getrecall接口



使用arthas的monito.]]></description><category></category></item><item><title><![CDATA[LogBack指定时间间隔生成日志文件]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/120185465</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/120185465</guid><author>DoasIsay</author><pubDate>Wed, 08 Sep 2021 18:20:25 +0800</pubDate><description><![CDATA[LogBack指定时间间隔生成日志文件

支持小时，分钟，秒

比如每2小时，每5分钟，每30秒产生一个日志文件


package dao.log;

import ch.qos.logback.core.joran.spi.NoAutoStart;
import ch.qos.logback.core.rolling.DefaultTimeBasedFileNamingAndTriggeringPolicy;
import lombok.Getter;
import lombok.Setter;

im]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程库的正常退出]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/108249683</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/108249683</guid><author>DoasIsay</author><pubDate>Wed, 26 Aug 2020 23:14:34 +0800</pubDate><description><![CDATA[https://github.com/DoasIsay/ToyCoroutine

我发现协程只能在对端主动断开连接后才能被动退出，并不能主动退出，做为服务端其实不应当主动断开连接退出，你不知道客户端还有没有数据要发，及客户端的发送缓冲区还有没有数据未发完，如果客户端没有在应用层实现ack及重试机制就有可能导致数据丢失，但协程不一定要只用在服务端

思来想去，我还是想，像在多线程，多进程编程环境中那样，在代码中设一全局变量isExit，当 kill进程时，在信号处理函数中设isExit为true时，进程可以]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程栈的动态按需增长]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/108229020</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/108229020</guid><author>DoasIsay</author><pubDate>Tue, 25 Aug 2020 21:16:35 +0800</pubDate><description><![CDATA[https://github.com/DoasIsay/ToyCoroutine

对于操作系统的任务（进程或线程）而言，任务所需的栈内存，堆内存，并不是任务启动后或发起内存申请（brk/mmap/malloc/new）后操作系统立即为其分配物理内存，而是先为其在进程的虚拟地址空间中找到一块空闲的空间标记其大小起止地址及访问权限，当CPU真正访问到任务未分配物理内存的虚拟页内的地址时MMU会产生一个内存缺页中断，此时在缺页中断处理中操作系统才会真正的为任务分配一页物理内存并更新进程的页表

如何检测协程是否]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程的errno与信号处理]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/108209647</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/108209647</guid><author>DoasIsay</author><pubDate>Mon, 24 Aug 2020 21:49:37 +0800</pubDate><description><![CDATA[https://github.com/DoasIsay/ToyCoroutine

每个线程都有自己的errno，那么协程是否也需要自已的errno？

如果这样写代码，那每个协程要有自已的errno









在hook的系统调用中当io读写不能满足时，就进行协程切换，在io可读写返回到用户代码后继续使用errno，此时的errno可能已经不是协程切换前的errno了，因为期间其它协程也会call系统调用，所以因在hook系统调用的代码中，在协程切换前先保存errno的值，因为协程恢复后会先判..]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程的跨线程负载均衡调度]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/108179215</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/108179215</guid><author>DoasIsay</author><pubDate>Sun, 23 Aug 2020 09:33:37 +0800</pubDate><description><![CDATA[https://github.com/DoasIsay/ToyCoroutine

其实一开始我并不想让ToyCoroutine支持多线程，多进程SO_REUSEADDR其实也挺好的，大家各跑各的互不影响，但在写代码时我又时刻考虑到多线程，毕竟，没有多线程间的同步协作那该是多么的无聊啊，，，

我在想当在多线程环境中使用协程库时，比如在一台8核的机器上，创建7个线程（调度器线程），每个线程负责一部分协程的调度执行，如何避免一些线程很忙导致协程调度超时，另一些线程却很空闲处于无协程可调度执行的状态？

把忙的]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程的互斥量与条件变量]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/107945072</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/107945072</guid><author>DoasIsay</author><pubDate>Tue, 11 Aug 2020 21:48:13 +0800</pubDate><description><![CDATA[https://github.com/DoasIsay/ToyCoroutine

在为ToyCoroutine的协程实现互斥量与条件变量时，测试过程中竟然死锁了，代码如下



我怀疑是producer，consumer使用了同一个条件变量进行协作导致的，测试时刚好创建了2个consumer协程，1个producer协程，当consumer1协程与producer协程都cond.wait在同一个条件变量时，由于调度原因consumer2调用cond.signal如果每次唤醒的都是consumer1，在最后]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之栈溢出检测]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/107396105</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/107396105</guid><author>DoasIsay</author><pubDate>Thu, 16 Jul 2020 22:38:53 +0800</pubDate><description><![CDATA[事情是这样的，在第一次因协程栈溢出导致的进程崩溃后，过了不知道多久由于代码量的增加，协程的栈又溢出了程序又崩溃了，多线程加协程对使用gdb调试而言并不是很友好，可能我还是不会使用gdb吧，从coredump中基本上找不到什么有助于问题定位的信息，有时候连个函数调用栈都没有，你都不知道运行到那个函数那行代码时出现了问题，如果是刚刚修改了代码程序就崩了，还可以大概确定是修改了的这部分代码出了问题，但是如果修改了很多代码，就需要大海捞针一样，用最原始的调试手段，在每个你觉得可疑的地方去print碰运气

于是我决]]></description><category></category></item><item><title><![CDATA[一个C/C++协程库的思考与实现之协程的简单调度]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/106954468</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/106954468</guid><author>DoasIsay</author><pubDate>Thu, 25 Jun 2020 23:09:07 +0800</pubDate><description><![CDATA[提供这样的协程使用接口，实在令人，，，





0.0.1代码的accept协程只能写的这样丑陋，因为协程创建后立马调度执行占用了CPU，只有当协程读写网络IO将被阻塞时才会主动让出CPU，这时调度器会获得CPU，当有新连接到来时accept协程才会被调度器调度恢复执行，所以要在新创建一个协程前要先保存accept协程的上下文环境做为一个返回点，以便将来返回



对于这么丑陋的代码我耿耿于怀，事实是我写代码的水平也确实不怎么样，确实丑陋

但我还是想写出像创建多线程那样的代码，比如这样



要写出..]]></description><category></category></item><item><title><![CDATA[linux任务的几种状态]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/106461946</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/106461946</guid><author>DoasIsay</author><pubDate>Sun, 31 May 2020 21:45:11 +0800</pubDate><description><![CDATA[linux任务的几种状态







而我们用ps，top看到的线程状态还需要转一下





R：任务正在CPU上运行，或已获取除CPU外所有的资源，正在等待调度运行



当linux任务无法获取所需资源时，如通过软中断陷入内核态调用会引起阻塞的系统调用read，accept，epoll_wait，select，futex等，不能继续运行下去时会在内核态改变自己的状态为阻塞态，然后进行任务切换



S：当阻塞可以被信号中断如net read，net write，accept，epoll_w...]]></description><category></category></item><item><title><![CDATA[关于java线程状态的一点小小的疑惑]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/106448048</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/106448048</guid><author>DoasIsay</author><pubDate>Sat, 30 May 2020 22:10:45 +0800</pubDate><description><![CDATA[事情是这样了，一个月黑风高的晚上，窗外的冷空气是那么的可口解渴，让人沉浸地无法自拔，人们都沉沉的睡去了，它正贪婪地，，，，突然，，，，



我这kafka不消费数据，是这个问题引起的？看着不像，正说着发来了线程堆栈



看着不像kafkaConsumer的线程栈啊，其实另一张图有就不发了没啥看头

如此如此

这般这般

，，，，，，，，，，，，，，，，，，，，，，



最后同事那边说是卡在与数据库通信上了也不是kafka消费的问题



但是，我看那个java线程的函数调用栈跟状态有点怪啊，明...]]></description><category></category></item><item><title><![CDATA[C++复杂类型-对象及虚函数表在可执行文件的存放位置与初始化时机]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/105877005</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/105877005</guid><author>DoasIsay</author><pubDate>Fri, 01 May 2020 13:31:12 +0800</pubDate><description><![CDATA[C++复杂类型-对象及虚函数表在可执行文件的存放位置与初始化时机





使用objdump -D -C反汇编-D会输出所有段，-C可以看到代码中的变量名



rodata 只读数据段







可看到只读数据段中有虚函数表(虚函数表的第一个4字节是空的，第二个4字节存放是typeinfo的地址，第三个4字节存放的是Test类的虚函数fun的地址)，和用于RTTI的Test类的类型...]]></description><category></category></item><item><title><![CDATA[如何使一个正在运行的进程慢下来？哦，不，是暂停]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/103917005</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/103917005</guid><author>DoasIsay</author><pubDate>Thu, 09 Jan 2020 23:42:26 +0800</pubDate><description><![CDATA[sleep?
renice?
ionice?
连着上了两周班，搞的闷了一脸痘，右下巴起了个大包，现在还没好，为了谁？为了兄弟姐妹不流泪？那个周六还是我生日啊，我加班到了23点，在路边吃了碗西红柿鸡蛋面就解决了，真是惨。第二天一大早又跑过去，我招谁了，惹谁了，有时候真是十分讨厌工作这么认真，这么敬业的自己，为什么就不能不负责点，，，
OK, this is a long story, let`s c...]]></description><category></category></item><item><title><![CDATA[你知不知Java如何解析C++通过tcp socket传过来的结构体啊]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/103797033</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/103797033</guid><author>DoasIsay</author><pubDate>Wed, 01 Jan 2020 22:40:43 +0800</pubDate><description><![CDATA[你：知不知道Java如何解析C++通过TcpSocket传过来的结构体啊
我：知道啊
不久前，接到一个任务，使用Java写一个flume的TcpSource做为服务端，用于接收C++客户端程序发送的未序列化的C++结构体并解析成Java对象，要完成这个需求的开发，首先需要了解一点点，结构体内存对齐，字节填充，CPU大小端及网络字节序，然后就是一点点反汇编，会写点点C++ /Java代码，会简单的使...]]></description><category></category></item><item><title><![CDATA[一条debug日志引发的性能问题排查]]></title><link>https://blog.youkuaiyun.com/DoasIsay/article/details/103450820</link><guid>https://blog.youkuaiyun.com/DoasIsay/article/details/103450820</guid><author>DoasIsay</author><pubDate>Mon, 09 Dec 2019 00:22:30 +0800</pubDate><description><![CDATA[又到周天了啊！每次到周天都会有问题啊啊啊！加班，加班，呃呃呃，本来已经想好了，这个周天，红烧老鳖，搞点豆瓣酱爆出红油，再来点青红二荆条什么的，最后撒上葱花香菜，哇！肯定好看又好吃。但是，XXX啊这个问题你要解决啊，下周大家都等着用数据。。。。。

我不知道大家知不知道？

反正我身边的程序员一般都是特别敬岗爱业，长的特别好看，说话特别好听，职业道德又特别高尚的人，电话秒接，信息秒回，一年365天，...]]></description><category></category></item></channel></rss>