惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
C
CERT Recently Published Vulnerability Notes
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Securelist
K
Kaspersky official blog
V
Vulnerabilities – Threatpost
C
Cisco Blogs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Hacker News: Ask HN
Hacker News: Ask HN
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
Security Affairs
Forbes - Security
Forbes - Security
Spread Privacy
Spread Privacy
C
CXSECURITY Database RSS Feed - CXSecurity.com
P
Palo Alto Networks Blog
H
Hacker News: Front Page
L
Lohrmann on Cybersecurity
Cloudbric
Cloudbric
S
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
I
InfoQ
人人都是产品经理
人人都是产品经理
PCI Perspectives
PCI Perspectives
月光博客
月光博客
爱范儿
爱范儿
Jina AI
Jina AI
WordPress大学
WordPress大学
N
News and Events Feed by Topic
Cyberwarzone
Cyberwarzone
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
小众软件
小众软件
Google Online Security Blog
Google Online Security Blog
W
WeLiveSecurity
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
博客园 - 司徒正美
Scott Helme
Scott Helme
AI
AI
L
LangChain Blog
A
Arctic Wolf
博客园 - 【当耐特】
量子位
S
SegmentFault 最新的问题
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
腾讯CDC
博客园 - 叶小钗
Last Week in AI
Last Week in AI
S
Secure Thoughts

博客园 - 张占岭

springboot~关于构造方法注入和字段注入的选择 apisix~OpenResty各阶段的介绍 keycloak~aud受众字段的作用及如何生成 wso2~关于workbuddy中mcp在wso2中的授权端点 k8s~避免调度资源碎片化 WEB安全~csrf介绍 WEB安全~DPoP的介绍 WEB安全~csp的介绍 什么是中间人攻击 WEB安全~xss的介绍 k8s~pod资源限制和JVM的XMX配置 关于对wso2和keycloak的token交换的调研 keycloak~实现OAuth 2.0 Token Exchange backstage~实体的介绍及它们的关系 backstage~openapi的接入与protobuf的对比 backstage~将java服务添加到backstage backstage~对接github和gitlab backstage~开始一个backstage应用 apisix~graphQL的支持 wso2几个核心项目介绍 docker~BuildKit的介绍 k8s~secret资源的使用 算法~时间戳计算两个日期是否为同天同时同分 wso2~4.5升级到4.6需要更新的数据表 backstage~Backstage的概述 springboot~jpa优雅的软删除能力 springboot~ImportBeanDefinitionRegistrar在自定义RPC框架中的使用 keycloak~分布式部署中会话过期清理机制 wso2~通过三方IDP的token置换wso2的token jmeter进行接口压测 Keycloak~infinispan中MergedUpdate中lifespanMs和maxIdleTimeMs wso2~添加mcp服务的注意点
keycloak~深入了解DefaultSegmentedDataContainer对象解决内存泄漏
张占岭 · 2026-01-30 · via 博客园 - 张占岭
  • 源码来自infinispan: git@github.com:infinispan/infinispan.git

基于Infinispan 内部架构的了解,让我为你详细解释 DefaultSegmentedDataContainer 中 TTL 的存储位置:

DefaultSegmentedDataContainer 中 TTL 的存储结构

核心结构层次

DefaultSegmentedDataContainer
│
├── DataSegment[] segments  ← 分段数组(根据 key 的 hash 分配)
│   │
│   └── ConcurrentHashMap<Object, InternalCacheEntry>
│       │
│       └── InternalCacheEntry<K, V>  ← 每个缓存条目对象
│           │
│           ├── key          : K         ← 缓存键
│           ├── value        : V         ← 缓存值
│           ├── metadata     : Metadata  ← 元数据(包含TTL信息)★
│           ├── created      : long      ← 创建时间戳
│           └── lastUsed     : long      ← 最后访问时间戳

TTL 信息的具体位置

TTL 不是存储在 DefaultSegmentedDataContainer 的直接属性中,而是在每个 InternalCacheEntry 对象的 Metadata 属性里。

Infinispan 中有多种 InternalCacheEntry 实现类,根据是否有过期时间分类:

实现类 特点 TTL 相关属性
ImmortalCacheEntry 永不过期 无 TTL 属性
MortalCacheEntry 有 lifespan lifespan, created
TransientCacheEntry 有 maxIdle maxIdle, lastUsed
TransientMortalCacheEntry 同时有两者 lifespan, maxIdle, created, lastUsed
MetadataImmortalCacheEntry 使用 Metadata 对象 metadata.lifespan(), metadata.maxIdle()
MetadataMortalCacheEntry 使用 Metadata 对象 metadata.lifespan(), metadata.maxIdle()

下面的缓存sessions表示永不过期,因为它的类型是ImmortalCacheEntry

图片

下面的缓存sessions是有过期时间的,它的类型是TransientMortalCacheEntry

图片

实际的 TTL 属性

对于 Keycloak 的会话缓存,通常使用 带 Metadata 的条目,TTL 信息在:

InternalCacheEntry entry = ...;

// 获取 lifespan (生命周期 TTL)
long lifespan = entry.getLifespan();      // 返回毫秒值,-1 表示永不过期

// 获取 maxIdle (空闲 TTL)  
long maxIdle = entry.getMaxIdle();        // 返回毫秒值,-1 表示永不过期

// 获取创建时间
long created = entry.getCreated();        // 创建时的时间戳

// 获取最后访问时间
long lastUsed = entry.getLastUsed();      // 最后访问的时间戳

// 检查是否过期
boolean expired = entry.isExpired(System.currentTimeMillis());

// 计算过期时间点
long expiryTime = entry.expiryTime();     // 返回具体的过期时间戳

在 JVM 调试时查看 TTL

如果你想在调试器中查看某个缓存项的 TTL,路径是:

DefaultSegmentedDataContainer
  └── segments (DataSegment[])
      └── [segment index] 
          └── entries (ConcurrentHashMap)
              └── [key]
                  └── InternalCacheEntry 对象
                      ├── metadata
                      │   ├── lifespan   ← 这里是 TTL(毫秒)
                      │   └── maxIdle    ← 这里是空闲超时(毫秒)
                      ├── created        ← 创建时间戳
                      └── lastUsed       ← 最后访问时间戳

过期判断逻辑

// 在 InternalCacheEntry 中的过期检查逻辑(简化版):
public boolean isExpired(long now) {
    // lifespan 检查
    if (lifespan > 0 && (created + lifespan) <= now) {
        return true;
    }
    // maxIdle 检查
    if (maxIdle > 0 && (lastUsed + maxIdle) <= now) {
        return true;
    }
    return false;
}

Keycloak 中 TTL 的设置来源

当 Keycloak 写入会话时,TTL 值来自 SessionTimeouts 类的计算:

// 写入缓存时设置 TTL
cache.put(key, value, lifespanMs, TimeUnit.MILLISECONDS, maxIdleMs, TimeUnit.MILLISECONDS);

这些值最终会被封装到 InternalCacheEntrymetadata 或对应属性中。

DefaultSegmentedDataContainer
│
├── DataSegment[] segments  ← 分段数组(根据 key 的 hash 分配)
│   │
│   └── ConcurrentHashMap<Object, InternalCacheEntry>
│       │
│       └── InternalCacheEntry<K, V>  ← 每个缓存条目对象
│           │
│           ├── key          : K         ← 缓存键
│           ├── value        : V         ← 缓存值
│           ├── metadata     : Metadata  ← 元数据(包含TTL信息)★
│           ├── created      : long      ← 创建时间戳
│           └── lastUsed     : long      ← 最后访问时间戳
InternalCacheEntry entry = ...;

// 获取 lifespan (生命周期 TTL)
long lifespan = entry.getLifespan();      // 返回毫秒值,-1 表示永不过期

// 获取 maxIdle (空闲 TTL)  
long maxIdle = entry.getMaxIdle();        // 返回毫秒值,-1 表示永不过期

// 获取创建时间
long created = entry.getCreated();        // 创建时的时间戳

// 获取最后访问时间
long lastUsed = entry.getLastUsed();      // 最后访问的时间戳

// 检查是否过期
boolean expired = entry.isExpired(System.currentTimeMillis());

// 计算过期时间点
long expiryTime = entry.expiryTime();     // 返回具体的过期时间戳
DefaultSegmentedDataContainer
  └── segments (DataSegment[])
      └── [segment index] 
          └── entries (ConcurrentHashMap)
              └── [key]
                  └── InternalCacheEntry 对象
                      ├── metadata
                      │   ├── lifespan   ← 这里是 TTL(毫秒)
                      │   └── maxIdle    ← 这里是空闲超时(毫秒)
                      ├── created        ← 创建时间戳
                      └── lastUsed       ← 最后访问时间戳
// 在 InternalCacheEntry 中的过期检查逻辑(简化版):
public boolean isExpired(long now) {
    // lifespan 检查
    if (lifespan > 0 && (created + lifespan) <= now) {
        return true;
    }
    // maxIdle 检查
    if (maxIdle > 0 && (lastUsed + maxIdle) <= now) {
        return true;
    }
    return false;
}
// 写入缓存时设置 TTL
cache.put(key, value, lifespanMs, TimeUnit.MILLISECONDS, maxIdleMs, TimeUnit.MILLISECONDS);