Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

优化threadlocal #822

Merged
merged 9 commits into from
Oct 7, 2023
Merged

优化threadlocal #822

merged 9 commits into from
Oct 7, 2023

Conversation

zt9788
Copy link
Contributor

@zt9788 zt9788 commented Oct 5, 2023

大量虚拟线程下ThreadLocal可能内存泄漏
缓存类型先用weak处理

@areyouok
Copy link
Collaborator

areyouok commented Oct 6, 2023

简单看了一下,有几个问题需要讨论一下:

  1. CacheContext是否需要修改?CacheThreadLocal是个很轻量的对象,每个虚拟线程一个,每次new一个出来,问题不大。
  2. 不能只改你要用到的部分,如果kryo5 encoder/decoder 改了,那么java/kryo encoder/decoder也应该修改
  3. kryo5 encoder/decoder现在的改法需要讨论。如果虚拟线程每次都new一个出来,那么放在ThreadLocal上面的缓存对象不会有像样的的命中率。kryo对象创建开销还挺大的,outputstream里面的byte[]也不小。是不是应该做个简单的对象池(自己做不要有依赖)

@zt9788
Copy link
Contributor Author

zt9788 commented Oct 6, 2023

简单看了一下,有几个问题需要讨论一下:

  1. CacheContext是否需要修改?CacheThreadLocal是个很轻量的对象,每个虚拟线程一个,每次new一个出来,问题不大。
  2. 不能只改你要用到的部分,如果kryo5 encoder/decoder 改了,那么java/kryo encoder/decoder也应该修改
  3. kryo5 encoder/decoder现在的改法需要讨论。如果虚拟线程每次都new一个出来,那么放在ThreadLocal上面的缓存对象不会有像样的的命中率。kryo对象创建开销还挺大的,outputstream里面的byte[]也不小。是不是应该做个简单的对象池(自己做不要有依赖)
  1. 不清除理论上也可以,只是会极大的延长ThreadLocal生命周期,造成少量的内存浪费

  2. 我再看一下,可能改漏了

  3. 开始也考虑对象池,考虑到复杂度增加,就先用弱引用来实现了
    目前看jackson/log4j2的方案,基本是引入无锁对象池, 目前看用的比较多的有jctool的MpmcAtomicArrayQueue,自己写一个也可以(或者分2个阶段来修改?)

    我回头先把2改了
    对象池的我参考一下,晚一点先简单实现一个

@zt9788
Copy link
Contributor Author

zt9788 commented Oct 6, 2023

用ArrayBlockingQueue做了一个简单对象池,是否可行?
如果可行,我就用这个把2,3重新改一下

public class ObjectPool<T> {
        private final ArrayBlockingQueue<T> queue;
        private final int size;
        private final ObjectFactory<T> factory;
        public ObjectPool(int size, ObjectFactory<T> factory) {
            this.size = size;
            this.factory = factory;
            queue = new ArrayBlockingQueue<>(size);
            for (int i = 0; i < size; i++) {
                queue.add(factory.create());
            }
        }
        public T borrowObject() {
            T t = queue.poll();
            if(t == null)
                return factory.create();
            return t;
        }
        public void returnObject(T obj) {
            if (obj == null) {
                return;
            }
            queue.offer(obj);
            factory.reset(obj);
        }

        public interface ObjectFactory<T> {
            T create();
            void reset(T obj);
        }
}

@areyouok
Copy link
Collaborator

areyouok commented Oct 6, 2023

简单看了一下,有几个问题需要讨论一下:

  1. CacheContext是否需要修改?CacheThreadLocal是个很轻量的对象,每个虚拟线程一个,每次new一个出来,问题不大。
  2. 不能只改你要用到的部分,如果kryo5 encoder/decoder 改了,那么java/kryo encoder/decoder也应该修改
  3. kryo5 encoder/decoder现在的改法需要讨论。如果虚拟线程每次都new一个出来,那么放在ThreadLocal上面的缓存对象不会有像样的的命中率。kryo对象创建开销还挺大的,outputstream里面的byte[]也不小。是不是应该做个简单的对象池(自己做不要有依赖)
  1. 不清除理论上也可以,只是会极大的延长ThreadLocal生命周期,造成少量的内存浪费
  2. 我再看一下,可能改漏了
  3. 开始也考虑对象池,考虑到复杂度增加,就先用弱引用来实现了
    目前看jackson/log4j2的方案,基本是引入无锁对象池, 目前看用的比较多的有jctool的MpmcAtomicArrayQueue,自己写一个也可以(或者分2个阶段来修改?)
    我回头先把2改了
    对象池的我参考一下,晚一点先简单实现一个

1 按我的理解,虚拟线程结束的时候,它的ThreadLocal会被gc吧。如果是这样,多个CacheThreadLoca好像问题不大?最多几十个字节。

@areyouok
Copy link
Collaborator

areyouok commented Oct 6, 2023

用ArrayBlockingQueue做了一个简单对象池,是否可行? 如果可行,我就用这个把2,3重新改一下

public class ObjectPool<T> {
        private final ArrayBlockingQueue<T> queue;
        private final int size;
        private final ObjectFactory<T> factory;
        public ObjectPool(int size, ObjectFactory<T> factory) {
            this.size = size;
            this.factory = factory;
            queue = new ArrayBlockingQueue<>(size);
            for (int i = 0; i < size; i++) {
                queue.add(factory.create());
            }
        }
        public T borrowObject() {
            T t = queue.poll();
            if(t == null)
                return factory.create();
            return t;
        }
        public void returnObject(T obj) {
            if (obj == null) {
                return;
            }
            queue.offer(obj);
            factory.reset(obj);
        }

        public interface ObjectFactory<T> {
            T create();
            void reset(T obj);
        }
}

简单来说,这样就可以了。

pool不能自动缩小的问题,就像以前output里面的字节数组一样,没有简单的好办法,我以前用weak ref,靠ygc来定期清理,也不是很好的方案。

@zt9788
Copy link
Contributor Author

zt9788 commented Oct 6, 2023

用ArrayBlockingQueue做了一个简单对象池,是否可行? 如果可行,我就用这个把2,3重新改一下

public class ObjectPool<T> {
        private final ArrayBlockingQueue<T> queue;
        private final int size;
        private final ObjectFactory<T> factory;
        public ObjectPool(int size, ObjectFactory<T> factory) {
            this.size = size;
            this.factory = factory;
            queue = new ArrayBlockingQueue<>(size);
            for (int i = 0; i < size; i++) {
                queue.add(factory.create());
            }
        }
        public T borrowObject() {
            T t = queue.poll();
            if(t == null)
                return factory.create();
            return t;
        }
        public void returnObject(T obj) {
            if (obj == null) {
                return;
            }
            queue.offer(obj);
            factory.reset(obj);
        }

        public interface ObjectFactory<T> {
            T create();
            void reset(T obj);
        }
}

简单来说,这样就可以了。

pool不能自动缩小的问题,就像以前output里面的字节数组一样,没有简单的好办法,我以前用weak ref,靠ygc来定期清理,也不是很好的方案。

OK,我明天按照这个方案再改一下2,3;

CacheThreadLocal确实可以回收,嗯,这块应该影响不大,我还原一下

@areyouok
Copy link
Collaborator

areyouok commented Oct 7, 2023

还有个java encoder/decoder也需要改

@CLAassistant
Copy link

CLAassistant commented Oct 7, 2023

CLA assistant check
All committers have signed the CLA.

@areyouok areyouok merged commit 45b5d8f into alibaba:master Oct 7, 2023
2 checks passed
@areyouok
Copy link
Collaborator

areyouok commented Oct 7, 2023

这个我合并了,还有一些地方在使用synchronized,你要改吗?

@zt9788
Copy link
Contributor Author

zt9788 commented Oct 7, 2023

这个我合并了,还有一些地方在使用synchronized,你要改吗?

我之前主要看了core.
那就我改吧 ,不过要下周预计周二、周三的样子

@zt9788 zt9788 deleted the optimize_tl branch October 7, 2023 10:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants