google人写的200 行 C 代码垃圾收集器

Eclipse内存配置实战:Heap与Metaspace调优指南 Java虚拟机(JVM)内存管理是保障IDE稳定运行的基础能力,其核心包括堆(Heap)和元空间(Metaspace)两大区域。Heap用于存储对象实例,受-Xms和-Xmx参数约束;Metaspace替代永久代,承载类元数据,默认无上限但需显式限制以避免系统内存耗尽。合理配置不仅提升Eclipse启动速度、热部署响应与GC效率,更能规避因类加载爆炸或静态引用泄漏引发的OutOfMemoryError。本文结合Spring Boot多模块、微服务及插件开发等典型场景,提供可验证的参数组合、MAT内存分析方法 阅读详情
#include <stdio.h>
#include <stdlib.h>

#define STACK_MAX 256

typedef enum {
  OBJ_INT,
  OBJ_PAIR
} ObjectType;

typedef struct sObject {
  ObjectType type;
  unsigned char marked;

  /* The next object in the linked list of heap allocated objects. */
  struct sObject* next;

  union {
    /* OBJ_INT */
    int value;

    /* OBJ_PAIR */
    struct {
      struct sObject* head;
      struct sObject* tail;
    };
  };
} Object;

typedef struct {
  Object* stack[STACK_MAX];
  int stackSize;

  /* The first object in the linked list of all objects on the heap. */
  Object* firstObject;

  /* The total number of currently allocated objects. */
  int numObjects;

  /* The number of objects required to trigger a GC. */
  int maxObjects;
} VM;

void assert(int condition, const char* message) {
  if (!condition) {
    printf("%s\n", message);
    exit(1);
  }
}

VM* newVM() {
  VM* vm = malloc(sizeof(VM));
  vm->stackSize = 0;
  vm->firstObject = NULL;
  vm->numObjects = 0;
  vm->maxObjects = 8;
  return vm;
}

void push(VM* vm, Object* value) {
  assert(vm->stackSize < STACK_MAX, "Stack overflow!");
  vm->stack[vm->stackSize++] = value;
}


Object* pop(VM* vm) {
  assert(vm->stackSize > 0, "Stack underflow!");
  return vm->stack[--vm->stackSize];
}

void mark(Object* object) {
  /* If already marked, we're done. Check this first to avoid recursing
     on cycles in the object graph. */
  if (object->marked) return;

  object->marked = 1;

  if (object->type == OBJ_PAIR) {
    mark(object->head);
    mark(object->tail);
  }
}

void markAll(VM* vm)
{
  for (int i = 0; i < vm->stackSize; i++) {
    mark(vm->stack[i]);
  }
}

void sweep(VM* vm)
{
  Object** object = &vm->firstObject;
  while (*object) {
    if (!(*object)->marked) {
      /* This object wasn't reached, so remove it from the list and free it. */
      Object* unreached = *object;

      *object = unreached->next;
      free(unreached);

      vm->numObjects--;
    } else {
      /* This object was reached, so unmark it (for the next GC) and move on to
       the next. */
      (*object)->marked = 0;
      object = &(*object)->next;
    }
  }
}

void gc(VM* vm) {
  int numObjects = vm->numObjects;

  markAll(vm);
  sweep(vm);

  vm->maxObjects = vm->numObjects * 2;

  printf("Collected %d objects, %d remaining.\n", numObjects - vm->numObjects,
         vm->numObjects);
}

Object* newObject(VM* vm, ObjectType type) {
  if (vm->numObjects == vm->maxObjects) gc(vm);

  Object* object = malloc(sizeof(Object));
  object->type = type;
  object->next = vm->firstObject;
  vm->firstObject = object;
  object->marked = 0;

  vm->numObjects++;

  return object;
}

void pushInt(VM* vm, int intValue) {
  Object* object = newObject(vm, OBJ_INT);
  object->value = intValue;

  push(vm, object);
}

Object* pushPair(VM* vm) {
  Object* object = newObject(vm, OBJ_PAIR);
  object->tail = pop(vm);
  object->head = pop(vm);

  push(vm, object);
  return object;
}

void objectPrint(Object* object) {
  switch (object->type) {
    case OBJ_INT:
      printf("%d", object->value);
      break;

    case OBJ_PAIR:
      printf("(");
      objectPrint(object->head);
      printf(", ");
      objectPrint(object->tail);
      printf(")");
      break;
  }
}

void test1() {
  printf("Test 1: Objects on stack are preserved.\n");
  VM* vm = newVM();
  pushInt(vm, 1);
  pushInt(vm, 2);

  gc(vm);
  assert(vm->numObjects == 2, "Should have preserved objects.");
}

void test2() {
  printf("Test 2: Unreached objects are collected.\n");
  VM* vm = newVM();
  pushInt(vm, 1);
  pushInt(vm, 2);
  pop(vm);
  pop(vm);

  gc(vm);
  assert(vm->numObjects == 0, "Should have collected objects.");
}

void test3() {
  printf("Test 3: Reach nested objects.\n");
  VM* vm = newVM();
  pushInt(vm, 1);
  pushInt(vm, 2);
  pushPair(vm);
  pushInt(vm, 3);
  pushInt(vm, 4);
  pushPair(vm);
  pushPair(vm);

  gc(vm);
  assert(vm->numObjects == 7, "Should have reached objects.");
}

void test4() {
  printf("Test 4: Handle cycles.\n");
  VM* vm = newVM();
  pushInt(vm, 1);
  pushInt(vm, 2);
  Object* a = pushPair(vm);
  pushInt(vm, 3);
  pushInt(vm, 4);
  Object* b = pushPair(vm);

  a->tail = b;
  b->tail = a;

  gc(vm);
  assert(vm->numObjects == 4, "Should have collected objects.");
}

void perfTest() {
  printf("Performance Test.\n");
  VM* vm = newVM();

  for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 20; j++) {
      pushInt(vm, i);
    }

    for (int k = 0; k < 20; k++) {
      pop(vm);
    }
  }
}

int main(int argc, const char * argv[]) {
  test1();
  test2();
  test3();
  test4();

  perfTest();

  return 0;
}





Baby's First Garbage Collector

December 08, 2013 — c, code, language

When I get stressed out and have too much to do, I have this paradoxical reaction where I escape from that by coming up with another thing to do. Usually it’s a tiny self-contained program that I can write and finish.

The other morning, I was freaking myself out about the book I’m working on and thestuff I have to do at work and a talk I’m preparing for Strange Loop, and all of the sudden, I thought, “I should write a garbage collector.”

Yes, I realize how crazy that paragraph makes me seem. But my faulty wiring is your free tutorial on a fundamental piece of programming language implementation! In about a hundred lines of vanilla C, I managed to whip up a basic mark-and-sweepcollector that actually, you know, collects.

Garbage collection is considered one of the more shark-infested waters of programming, but in this post, I’ll give you a nice kiddie pool to paddle around in. (There may still be sharks in it, but at least it will be shallower.)

Reduce, reuse, recycle

The basic idea behind garbage collection is that the language (for the most part) appears to have access to infinite memory. The developer can just keep allocating and allocating and allocating and, as if by magic, it never fails.

Of course, machines don’t have infinite memory. So the way the implementation does this is that when it needs to allocate a bit of memory and it realizes it’s running low, it collects garbage.

“Garbage” in this context means memory it previously allocated that is no longer being used. For the illusion of infinite memory to work, the language needs to be very safe about “no longer being used”. It would be no fun if random objects just started getting reclaimed while your program was trying to access them.

In order to be collectible, the language has to ensure there’s no way for the program to use that object again. If it can’t get a reference to the object, then it obviously can’t use it again. So the definition of “in use” is actually pretty simple:

  1. Any object that’s being referenced by a variable that’s still in scope is in use.
  2. Any object that’s referenced by another object that’s in use is in use.

The second rule is the recursive one. If object A is referenced by a variable, and it has some field that references object B, then B is in use since you can get to it through A.

The end result is a graph of reachable objects—all of the objects in the world that you can get to by starting at a variable and traversing through objects. Any object notin that graph of reachable objects is dead to the program and its memory is ripe for a reaping.

Marking and sweeping

There’s a bunch of different ways you can implement the process of finding and reclaiming all of the unused objects, but the simplest and first algorithm ever invented for it is called “mark-sweep”. It was invented by John McCarthy, the man who invented Lisp and beards, so you implementing it now is like communing with one of the Elder Gods, but hopefully not in some Lovecraftian way that ends with you having your mind and retinas blasted clean.

It works almost exactly like our definition of reachability:

  1. Starting at the roots, traverse the entire object graph. Every time you reach an object, set a “mark” bit on it to true.
  2. Once that’s done, find all of the objects whose mark bits are not set and delete them.

That’s it. I know, you could have come up with that, right? If you had, you’d be the author of a paper cited hundreds of times. The lesson here is that to be famous in CS, you don’t have to come up with really smart stuff, you just have to come up with dumb stuff first.

A pair of objects

Before we can get to implementing those two steps, let’s get a couple of preliminaries out of the way. We won’t be actually implementing an interpreter for a language—no parser, bytecode, or any of that foolishness—but we do need some minimal amount of code to create some garbage to collect.

Let’s play pretend that we’re writing an interpreter for a little language. It’s dynamically typed, and has two types of objects: ints and pairs. Here’s an enum to identify an object’s type:

typedef enum {
  OBJ_INT,
  OBJ_PAIR
} ObjectType;

A pair can be a pair of anything, two ints, an int and another pair, whatever. You can go surprisingly far with just that. Since an object in the VM can be either of these, the typical way in C to implement it is with a tagged union.

We’ll define it thusly:

typedef struct sObject {
  ObjectType type;

  union {
    /* OBJ_INT */
    int value;

    /* OBJ_PAIR */
    struct {
      struct sObject* head;
      struct sObject* tail;
    };
  };
} Object;

The main Object struct has a type field that identifies what kind of value it is— either an int or a pair. Then it has a union to hold the data for the int or pair. If your C is rusty, a union is a struct where the fields overlap in memory. Since a given object can only be an int or a pair, there’s no reason to have memory in a single object for all three fields at the same time. A union does that. Groovy.

A minimal virtual machine

Now we can wrap that in a little virtual machine structure. Its role in this story is to have a stack that stores the variables that are currently in scope. Most language VMs are either stack-based (like the JVM and CLR) or register-based (like Lua). In both cases, there is actually still a stack. It’s used to store local variables and temporary variables needed in the middle of an expression.

We’ll model that explicitly and simply like so:

#define STACK_MAX 256

typedef struct {
  Object* stack[STACK_MAX];
  int stackSize;
} VM;

Now that we’ve got our basic data structures in place, let’s slap together a bit of code to create some stuff. First, let’s write a function that creates and initializes a VM:

VM* newVM() {
  VM* vm = malloc(sizeof(VM));
  vm->stackSize = 0;
  return vm;
}

Once we’ve got a VM, we need to be able to manipulate its stack:

void push(VM* vm, Object* value) {
  assert(vm->stackSize < STACK_MAX, "Stack overflow!");
  vm->stack[vm->stackSize++] = value;
}

Object* pop(VM* vm) {
  assert(vm->stackSize > 0, "Stack underflow!");
  return vm->stack[--vm->stackSize];
}

OK, now that we can stick stuff in “variables”, we need to be able to actually create objects. First a little helper function:

Object* newObject(VM* vm, ObjectType type) {
  Object* object = malloc(sizeof(Object));
  object->type = type;
  return object;
}

That does the actual memory allocation and sets the type tag. We’ll be revisiting this in a bit. Using that, we can write functions to push each kind of object onto the VM’s stack:

void pushInt(VM* vm, int intValue) {
  Object* object = newObject(vm, OBJ_INT);
  object->value = intValue;
  push(vm, object);
}

Object* pushPair(VM* vm) {
  Object* object = newObject(vm, OBJ_PAIR);
  object->tail = pop(vm);
  object->head = pop(vm);

  push(vm, object);
  return object;
}

And that’s it for our little VM. If we had a parser and an interpreter that called those functions, we’d have an honest to God language on our hands. And, if we had infinite memory, it would even be able to run real programs. Since we don’t, let’s start collecting some garbage.

Marky mark

The first phase is marking. We need to walk all of the reachable objects and set their mark bit. The first thing we need then is to add a mark bit to Object:

typedef struct sObject {
  unsigned char marked;
  /* Previous stuff... */
} Object;

When we create a new object, we’ll modify newObject() to initialize marked to zero. To mark all of the reachable objects, we start with the variables that are in memory, so that means walking the stack. That looks like this:

void markAll(VM* vm)
{
  for (int i = 0; i < vm->stackSize; i++) {
    mark(vm->stack[i]);
  }
}

That in turn calls mark. We’ll build that in phases. First:

void mark(Object* object) {
  object->marked = 1;
}

This is the most important bit, literally. We’ve marked the object itself as reachable, but remember we also need to handle references in objects: reachability is recursive. If the object is a pair, its two fields are reachable too. Handling that is simple:

void mark(Object* object) {
  object->marked = 1;

  if (object->type == OBJ_PAIR) {
    mark(object->head);
    mark(object->tail);
  }
}

But there’s a bug here. Do you see it? We’re recursing now, but we aren’t checking for cycles. If you have a bunch of pairs that point to each other in a loop, this will overflow the stack and crash.

To handle that, we just need to bail out if we get to an object that we’ve already processed. So the complete mark() function is:

void mark(Object* object) {
  /* If already marked, we're done. Check this first
     to avoid recursing on cycles in the object graph. */
  if (object->marked) return;

  object->marked = 1;

  if (object->type == OBJ_PAIR) {
    mark(object->head);
    mark(object->tail);
  }
}

Now we can call markAll() and it will correctly mark every reachable object in memory. We’re halfway done!

Sweepy sweep

The next phase is to sweep through all of the objects we’ve allocated and free any of them that aren’t marked. But there’s a problem here: all of the unmarked objects are, by definition, unreachable! We can’t get to them!

The VM has implemented the language’s semantics for object references: so we’re only storing pointers to objects in variables and the pair elements. As soon as an object is no longer pointed to by one of those, we’ve lost it entirely and actually leaked memory.

The trick to solve this is that the VM can have its own references to objects that are distinct from the semantics that are visible to the language user. In other words, we can keep track of them ourselves.

The simplest way to do this is to just maintain a linked list of every object we’ve ever allocated. We’ll extend Object itself to be a node in that list:

typedef struct sObject {
  /* The next object in the list of all objects. */
  struct sObject* next;

  /* Previous stuff... */
} Object;

The VM will keep track of the head of that list:

typedef struct {
  /* The first object in the list of all objects. */
  Object* firstObject;

  /* Previous stuff... */
} VM;

In newVM() we’ll make sure to initialize firstObject to NULL. Whenever we create an object, we add it to the list:

Object* newObject(VM* vm, ObjectType type) {
  Object* object = malloc(sizeof(Object));
  object->type = type;
  object->marked = 0;

  /* Insert it into the list of allocated objects. */
  object->next = vm->firstObject;
  vm->firstObject = object;

  return object;
}

This way, even if the language can’t find an object, the language implementationstill can. To sweep through and delete the unmarked objects, we just need to traverse the list:

void sweep(VM* vm)
{
  Object** object = &vm->firstObject;
  while (*object) {
    if (!(*object)->marked) {
      /* This object wasn't reached, so remove it from the list
         and free it. */
      Object* unreached = *object;

      *object = unreached->next;
      free(unreached);
    } else {
      /* This object was reached, so unmark it (for the next GC)
         and move on to the next. */
      (*object)->marked = 0;
      object = &(*object)->next;
    }
  }
}

That code is a bit tricky to read because of that pointer to a pointer, but if you work through it, you can see it’s pretty straightforward. It just walks the entire linked list. Whenever it hits an object that isn’t marked, it frees its memory and removes it from the list. When this is done, we will have deleted every unreachable object.

Congratulations! We have a garbage collector! There’s just one missing piece: actually calling it. First let’s wrap the two phases together:

void gc(VM* vm) {
  markAll(vm);
  sweep(vm);
}

You couldn’t ask for a more obvious mark-sweep implementation. The trickiest part is figuring out when to actually call this. What does “low on memory” even mean, especially on modern computers with near-infinite virtual memory?

It turns out there’s no precise right or wrong answer here. It really depends on what you’re using your VM for and what kind of hardware it runs on. To keep this example simple, we’ll just collect after a certain number of allocations. That’s actually how some language implementations work, and it’s easy to implement.

We’ll extend VM to track how many we’ve created:

typedef struct {
  /* The total number of currently allocated objects. */
  int numObjects;

  /* The number of objects required to trigger a GC. */
  int maxObjects;

  /* Previous stuff... */
} VM;

And then initialize them:

VM* newVM() {
  /* Previous stuff... */

  vm->numObjects = 0;
  vm->maxObjects = INITIAL_GC_THRESHOLD;
  return vm;
}

The INITIAL_GC_THRESHOLD will be the number of objects at which you kick off thefirst GC. A smaller number is more conservative with memory, a larger number spends less time on garbage collection. Adjust to taste.

Whenever we create an object, we increment numObjects and run a collection if it reaches the max:

Object* newObject(VM* vm, ObjectType type) {
  if (vm->numObjects == vm->maxObjects) gc(vm);

  /* Create object... */

  vm->numObjects++;
  return object;
}

I won’t bother showing it, but we’ll also tweak sweep() to decrement numObjectsevery time it frees one. Finally, we modify gc() to update the max:

void gc(VM* vm) {
  int numObjects = vm->numObjects;

  markAll(vm);
  sweep(vm);

  vm->maxObjects = vm->numObjects * 2;
}

After every collection, we update maxObjects based on the number of live objects left after the collection. The multiplier there lets our heap grow as the number of living objects increases. Likewise, it will shrink automatically if a bunch of objects end up being freed.

Simple

You made it! If you followed all of this, you’ve now got a handle on a simple garbage collection algorithm. If you want to see it all together, here’s the full code. Let me stress here that while this collector is simple, it isn’t a toy.

There are a ton of optimizations you can build on top of this (and in things like GC and programming languages, optimization is 90% of the effort), but the core code here is a legitimate real GC. It’s very similar to the collectors that were in Ruby and Lua until recently. You can ship production code that uses something exactly like this. Now go build something awesome!


通义灵码PyCharm深度配置与工程化用法指南 通义灵码并非传统AI代码补全工具,而是一个深度集成PyCharm AST解析、本地符号索引与项目语义图谱的智能编程助手。其核心原理在于将大模型轻量化推理引擎与Python工程知识库耦合,实现上下文感知的代码生成与验证。技术价值体现在跨文件类型推导、测试用例边界覆盖、技术债可视化及文档-代码双向同步四大工程场景。区别于Copilot等远程调用模式,它依赖本地服务进程(aliyun-llm-service)、精准Python环境(如pydantic>=2.0、cryptography>=38.0)及Git/ID 阅读详情

相关推荐

散列表工程实践:从HashMap性能雪崩到高并发优化

散列表是现代系统中最常用也最易被误用的核心数据结构,其理论上的O(1)平均查找性能,在真实场景中常因哈希冲突、扩容风暴、并发阻塞和内存布局缺陷而严重退化。理解其底层原理——包括哈希函数设计(如String.hashCode的偏斜性)、2的幂容量与位运算优化、Node对象内存开销(32字节起步)、以及ConcurrentHashMap的桶级锁机制——是保障亚毫秒响应与零GC停顿的前提。本文聚焦Java生态下的高频痛点:HashMap resize导致的CPU飙升、ConcurrentHashMap get延迟

xiang_fu的博客 443

自己动手写垃圾收集器

之前写过几篇自己动手系列的文章,简要实现了栈,二叉堆,malloc等函数,对于垃圾收集器,一直也有所耳闻。像python中主要使用引用计数手段来管理内存,为了解决循环引用的问题,引入了分代收集和标记-清除方式。当然python中可能产生循环引用的只可能是容器类对象如list,dict,class等,而像int,string是不可能产生循环引用的。当然python中的垃圾收集器实现是比较复杂的,我也没

__七把刀__ 2759

Ubuntu 22.04 生产级 Jitsi Meet 部署实战:高并发、LDAP 对接与 WebRTC 稳定性调优

Jitsi Meet 是基于 WebRTC 的开源音视频协作平台,其核心价值在于完全可控的私有化部署能力。理解 WebRTC 的 ICE 候选者协商、STUN/TURN 穿透机制及拥塞控制(GCC)原理,是保障百人级会议低延迟、不掉帧的技术基础。在 Ubuntu 22.04 这一长期支持版本上,得益于内核 5.15 对 WebRTC 的深度优化和 systemd 249 的可靠服务管理,可构建高可用、可扩展的分布式架构——包括独立 TURN 服务器、JVB 横向扩展与 Nginx SSL 终止等关键设计。本

weixin_30570101的博客 362

[GC]一个简单的Garbage Collector的实现

前言:     最近看了google的工程师写的一个非常简单的垃圾收集器,大概200多行C代码,感叹大牛总能够把复杂的东西通过很简单的语言和代码表达出来。为了增加自己的理解,决定把大牛的想法和代码分析一遍,与大家分享,顺便结合wikipedia,复习下GC的基本概念。   相信大家在写程序的过程中都遇到内存管理的问题,诸如malloc/delete、new/free等,C/C++需要程序员主动...

weixin_30552635的博客 133

构建系统性性能优化框架:从数据驱动到架构实践

系统性能优化是软件工程中的核心挑战,其本质在于通过科学方法提升资源利用效率与响应速度。从原理层面看,优化需遵循数据驱动原则,基于吞吐量、响应时间、错误率等关键指标建立性能基准,而非依赖主观感受。技术价值体现在通过精准定位瓶颈,如利用arthas进行应用层性能剖析或分析数据库慢查询,实现高性价比的改进。在应用场景上,优化贯穿于计算、I/O、并发及分层架构等环节,例如通过缓存策略减少不必要的CPU消耗,或使用连接池化降低网络延迟。这些实践最终收敛于构建一套从认知到实施的系统性性能优化框架,帮助开发者科学应对系统

weixin_34101784的博客 393

Metabase Docker部署最佳实践:Ubuntu 20.04生产环境稳定方案

Metabase 是一款开源轻量级 BI 工具,其容器化部署依赖底层操作系统与运行时环境的深度协同。在 Linux 环境中,Docker 提供了标准化的隔离与分发能力,而 Ubuntu 20.04 LTS 凭借内核 5.4、systemd 245 及默认启用的 cgroups v2,成为当前最稳定的宿主平台——它解决了资源隔离失效、JVM 内存限制失准、时区与字体渲染异常等关键问题。该组合显著降低运维复杂度,支撑数百并发用户下的高可用查询服务,并广泛应用于中小型企业数据看板、SaaS 运营分析及内部数据民主

weixin_33965305的博客 425

Ubuntu 20.04 安装 JDK 17 的版本选型与避坑指南

Java 是一种跨平台的高级编程语言,其运行依赖于特定版本的 JDK(Java Development Kit)。JDK 的版本选择并非简单执行 apt install 命令,而是需结合操作系统生命周期、LTS 支持策略与应用兼容性进行综合判断。Ubuntu 20.04 作为长期支持(LTS)发行版,原生适配 OpenJDK 11 和 JDK 17 这两个 LTS 版本,但默认源中 JDK 17 需通过 universe 仓库启用,且存在 headless 版本、alternatives 管理、JAVA_H

weixin_30697239的博客 339

2026年AI大模型面试题整理(含答案).zip

2026年AI大模型面试题整理(含答案),共76份。供大家学习参阅。 AI大模型八股文(102).pdf Transformer面试题总结97道.pdf 大模型 LLM 最全八股和答案.pdf 大模型 RAG 经验面.pdf 大模型LLMS面试宝典.pdf 大模型岗位面试全纪录.pdf 大模型常考面试题总结+答案.pdf 大模型常见面试题及解答1.pdf 大模型常见面试题及解答2.pdf 大模型常见面试题及解答3.pdf 大模型校招面试题.pdf 50个精通AI大模型面试题.pdf 52道大模型八股文面试题\1-大模型(LLMs)基础面.docx 52道大模型八股文面试题\10-LLMs+训练经验帖.docx 52道大模型八股文面试题\11-大模型(LLMs)langchain+面.docx 52道大模型八股文面试题\12-多轮对话中让AI保持长期记忆的8种优化方式篇.docx 52道大模型八股文面试题\13-基于langchain+RAG问答应用实战.docx 52道大模型八股文面试题\14-基于LLM+向量库的文档对话+经验面.docx 52道大模型八股文面试题\15-大模型+RAG+经验面.docx 52道大模型八股文面试题\16-LLM文档对话+——+pdf解析关键问题.docx 52道大模型八股文面试题\17-大模型(LLMs)RAG+版面分析——表格识别方法篇.docx 52道大模型八股文面试题\18-大模型(LLMs)RAG+版面分析——文本分块面.docx 52道大模型八股文面试题\19-大模型外挂知识库优化——如何利用大模型辅助召回?.docx 52道大模型八股文面试题\2-Layer+normalization+篇.docx 52道大模型八股文面试题\20-大模型外挂知识库优化——负样本样本挖掘篇.docx 52道大模型八股文面试题\21-RAG(Retrieval-Augmented+Generation)评测面.docx 52道大模型八股文面试题\22-检索增强生成(RAG)+优化策略篇6.docx 52道大模型八股文面试题\23-大模型(LLMs)RAG+——+关键痛点及对应解决方案.docx 52道大模型八股文面试题\24-大模型(LLMs)RAG+优化策略+——+RAG-Fusion篇.docx 52道大模型八股文面试题\25-Graph+RAG+面+—+一种+基于知识图谱的大模型检索增强实现策略.docx 52道大模型八股文面试题\26-大模型(LLMs)参数高效微调(PEFT)+面.docx 52道大模型八股文面试题\27-适配器微调(Adapter-tuning)篇.docx 52道大模型八股文面试题\28-提示学习(Prompting)篇.docx 52道大模型八股文面试题\29-LoRA+系列篇.docx 52道大模型八股文面试题\3-LLMs+激活函数篇.docx 52道大模型八股文面试题\30-如何使用+PEFT库+中+LoRA?.docx 52道大模型八股文面试题\31-大模型(LLMs)推理面.docx 52道大模型八股文面试题\32-大模型(LLMs)增量预训练篇.docx 52道大模型八股文面试题\33-增量预训练(Pretrain)样本拼接篇.docx 52道大模型八股文面试题\34-基于lora的llama2二次预训练.docx 52道大模型八股文面试题\35-大模型(LLMs)评测面.docx 52道大模型八股文面试题\36-大模型(LLMs)强化学习面.docx 52道大模型八股文面试题\37-大模型(LLMs)强化学习——RLHF及其变种面.docx 52道大模型八股文面试题\38-大模型(LLMs)强化学习——+PPO+面.docx 52道大模型八股文面试题\39-强化学习在自然语言处理下的应用篇.docx 52道大模型八股文面试题\4-Attention+升级面.docx 52道大模型八股文面试题\40-大模型(LLMs)训练集面.docx 52道大模型八股文面试题\41-大模型(LLMs)LLM生成SFT数据方法面.docx 52道大模型八股文面试题\42-大模型(LLMs)显存问题面.docx 52道大模型八股文面试题\43-显存优化策略篇.docx 52道大模型八股文面试题\44-大模型(LLMs)分布式训练面.docx 52道大模型八股文面试题\45-图解分布式训练(一)+——+流水线并行(Pipeline+Parallelism).docx 52道大模型八股文面试题\46-图解分布式训练(二)+——+nn.DataParallel篇.docx 52道大模型八股文面试题\47-图解分布式训练(三)+——+nn.parallel.DistributedDataParallel.docx 52道大模型八股文面试题\48-图解分布式训练(四)+——+torch.multiprocessing+详细解析0.docx 52道大模型八股文面试题\49-图解分布式训练(五)+——+AMP混合精度训练+详细解析.docx 52道大模型八股文面试题\5-transformers+操作篇.docx 52道大模型八股文面试题\50-图解分布式训练(六)——+Pytorch的+DeepSpeed+详细解析.docx 52道大模型八股文面试题\51-图解分布式训练(七)——+accelerate+分布式训练+详细解析.docx 52道大模型八股文面试题\52-图解分布式训练(八)——+ZeRO+学习.docx 52道大模型八股文面试题\6-LLMs+损失函数篇.docx 52道大模型八股文面试题\7-相似度函数篇.docx 52道大模型八股文面试题\8-大模型(LLMs)进阶面.docx 52道大模型八股文面试题\9-大模型(LLMs)微调面.docx 李老师AI大模型面试题资料\Agent Loop&Loop Engineering面试10连问.md 李老师AI大模型面试题资料\Agent Loop面试10连问.pptx 李老师AI大模型面试题资料\AI大模型面试题.png 李老师AI大模型面试题资料\DeepSeek Harness 10连问.pptx 李老师AI大模型面试题资料\FDE岗位常见面试题.pptx 李老师AI大模型面试题资料\Milvus3.0新特性.pptx 李老师AI大模型面试题资料\RAG码士学习平台知识库项目.png 李老师AI大模型面试题资料\RAG码士学习平台知识库项目.pptx 连老师AI大模型面试资料\Langchain.txt 连老师AI大模型面试资料\连老师LangChain面试题:httpscloud.fynote.comsharesZUIogPG4.txt

Java项目运维总结记录

一、常见故障 1.1、Java项目CPU耗用突增100%分析定位 1)执行top命令确认当前占用cpu的的java进程;以下是一些快捷键: ?:显示在top当中可以输入的命令 P:以CPU的使用资源排序显示 M:以内存的使用资源排序显示 N:以pid排序显示 T:由进程使用的时间累计排序显示 k:给某一个pid一个信号。可以用来杀死进程 r:给某个pid重新定制一个nice值(即优先级) q:退出top(用ctrl+c也可以退出top)。 2)确认异常进程的具体线程:上述界面按H键或执行top -Hp ja

企业实战系列集 ●●● https://ximenjianxue.blog.youkuaiyun.com 1666

【Web服务器运维】基于Nginx与Keepalived的高可用负载均衡系统部署:实现故障自动切换与虚拟IP管理

内容概要:本文详细介绍了如何通过Nginx与Keepalived实现高可用的负载均衡架构。首先讲解了Nginx的安装部署流程,包括依赖环境的准备、源码解压编译、启动及配置重载;接着介绍了Keepalived的安装步骤及其服务管理方式;重点在于通过配置Keepalived的主备节点(MASTER/BACKUP),结合VRRP协议和虚拟IP(VIP)实现故障自动切换,并通过自定义脚本nginx_check.sh实时检测Nginx运行状态,确保服务高可用;最后补充了在云环境中因组播限制导致心跳不稳定时,应改用单播(unicast)方式进行通信的解决方案。; 适合人群:具备Linux系统操作基础、熟悉网络基础知识,从事运维、DevOps或Web服务部署的技术人员,尤其是工作1-3年的工程师。; 使用场景及目标:①搭建高可用的Web负载均衡系统,避免单点故障;②掌握Nginx与Keepalived协同工作的原理与实战配置方法;③应用于生产环境中提升服务稳定性与容灾能力。; 阅读建议:学习时应结合实验环境动手操作,重点关注keepalived.conf配置差异与nginx_check.sh脚本逻辑,理解VRRP机制及单播替代组播的实际应用场景,注意根据实际网络环境调整IP与网卡参数。

三电平Buck直流变换器双闭环、单闭环、开环仿真【附参考文献】(Simulink仿真实现)

内容概要:本文档系统介绍了三电平Buck直流变换器在Simulink环境下的开环、单闭环与双闭环控制系统的建模仿真方法,涵盖系统建模、控制策略设计及动态性能对比分析。通过构建不同控制结构,深入探讨电压调节精度、系统响应速度、抗干扰能力及稳定性差异,重点剖析双闭环控制中电压外环与电流内环的协同作用机制,揭示其在抑制输出纹波、提升负载适应性方面的优势,帮助读者掌握多电平DC-DC变换器的核心控制原理与工程实现技术;文档还提供了详实的仿真参数设置与参考文献,便于理论验证与实践复现。; 适合人群:电力电子、自动化、电气工程及其相关专业的高校本科生、研究生、科研人员,以及从事电源系统、新能源变换器开发的工程技术人员。; 使用场景及目标:①作为高校电力电子课程的教学案例,辅助学生理解Buck变换器多层次控制策略的设计思路与性能差异;②为科研项目中高效直流变换系统的仿真研究提供可复用的技术模板;③指导工业界在高精度电源设计中优化控制器参数,提升系统动态响应与稳定性。; 阅读建议:建议结合Simulink仿真模型同步操作,对照文档逐步搭建各控制结构,重点观察不同闭环配置下输出电压的瞬态与稳态表现,深入理解PI参数整定、环路耦合影响及系统频域特性的关联性,从而全面提升对电力电子系统控制设计的综合把握能力。

COMSOL 6.3企业级部署:安装、验证与NUMA感知性能调优

COMSOL作为主流多物理场仿真平台,其安装配置远超常规软件——本质是面向HPC环境的系统级工程。理解Java运行时兼容性、MPI并行架构、GPU加速依赖链及许可证协议机制,是保障求解器稳定高效运行的前提。尤其在Windows Server/专业版环境下,TLS策略冲突、NUMA内存绑定失效、驱动版本错配等确定性故障,会直接导致加速比断崖式下跌。本文聚焦COMSOL 6.3真实部署场景,结合OpenMPI 4.0迁移与Parallel Meshing Engine v2特性,解析从系统准备、静默安装、许可证

weixin_33860553的博客 528

从Podfile到分享成功:ShareSDK小红书模块集成全流程实战(附视频分享代码)

本文详细介绍了iOS应用如何通过ShareSDK集成小红书分享功能的全流程,包括环境配置、SDK初始化、图片和视频分享实现,以及常见问题排查和性能优化策略。特别针对视频分享这一高频需求场景,提供了完整的代码示例和实战技巧,帮助开发者快速实现社交分享功能。

weixin_42540248的博客 226

Ubuntu 22.04 手动部署 Jitsi Meet 全流程指南

WebRTC 实时音视频系统是现代远程协作的基础设施,其核心在于信令控制、媒体转发与 NAT 穿透三大能力。Jitsi Meet 作为开源可自托管的 WebRTC 解决方案,依赖 Prosody(XMPP 信令)、Jicofo(会议协调)和 JVB(SFU 媒体桥)协同工作,对操作系统底层网络栈、Java 运行时及 TLS 证书管理高度敏感。Ubuntu 22.04 LTS 凭借长期支持内核、OpenSSL 3.0.2 和稳定 APT 生态,成为生产环境部署 Jitsi Meet 的高兼容性基座。本文聚焦原

weixin_30892889的博客 356

IEEE Access投稿全流程解析:从初次提交到最终接收的完整指南

本文详细解析了IEEE Access期刊从初次投稿到最终接收的全流程,包括ORCID注册、论文投稿七步法、回稿再投流程及最终版提交等关键步骤。特别强调了4-6周快速同行评审的特点,为研究者提供了一份实用的投稿指南,帮助高效完成IEEE Access期刊投稿。

weixin_29273849的博客 915

gesp c++ 五级知识点

gesp c++ 五级知识点

MMD.然大大 2009

Sol2实战指南:现代C++与Lua无缝集成的核心技术与工程实践

在软件架构中,脚本语言与系统级语言的集成是实现逻辑解耦与动态扩展的关键技术。其核心原理在于通过绑定机制,在静态类型语言(如C++)与动态类型语言(如Lua)之间建立类型安全的通信桥梁,从而兼顾性能与灵活性。这项技术的价值在于,它允许开发者将性能敏感的核心模块用C++实现,同时将易变的业务逻辑、配置或玩法交由Lua处理,极大地提升了开发效率与系统的可维护性。典型的应用场景包括游戏引擎的脚本系统、需要热更新的桌面应用以及工业自动化中的插件架构。本文聚焦于**Sol2**这一现代C++绑定库,它通过先进的模板元编

weixin_30615767的博客 341

# YOLOv11-seg改进系列 | 引入CVPR MetaFormer的C3k2_PoolingFormerCGLU模块,池化Token混合+CGLU门控MLP

本文引入 CVPR 2022 论文(MetaFormer/PoolFormer)提出的 MetaFormer 元架构设计,以Pooling Token 混合器 + ConvolutionalGLU(CGLU)MLP构成,将其封装为,用于替换 YOLOv11-seg 的 C3k2 块。对比维度C3k2(基线)C3k2_PoolingFormerCGLU(本文)参数量(n scale)2.46M≈2.49M9.6≈9.69.7(+1.0%)架构范式单阶段卷积MetaFormer 双阶段。

qq_44224801的博客 845

每周技术面试高频题汇总:算法、系统与底层实战精析完整实战指南

从本周的热议题目来看,面试官越来越倾向于“场景化”算法不再死记硬背:比如区间问题,会结合会议室调度、排班系统等实际场景。底层细节决定成败:特别是嵌入式方向,对内存对齐、栈帧布局的考察非常深入,甚至涉及汇编级优化。代码规范:在 LeetCode 讨论区,大家不仅关注 AC(Accepted),更关注代码的可读性和边界条件的处理(如空指针、数组越界)。最后的小贴士如果你正在备战大厂,建议重点复习贪心算法的几种原型(区间、跳跃、股票),并深入了解一门语言的内存模型。

热爱技术与前沿创新,深耕科技领域,在科创中精进自我;探索技术乐趣,分享技术干货与成长心得,以技术为伴,热爱生活,在科创与生活中双向成长。 486

手把手教你学Simulink——基于智能电网与AI融合的场景实例:强化学习在并网逆变器控制中的应用

本文介绍了如何利用Simulink和强化学习工具包实现并网逆变器的智能控制。针对传统PI控制方法的局限性,提出采用强化学习(RL)构建自适应控制系统。通过详细步骤展示了从建立主电路模型、设计强化学习环境、选择训练智能体(如PPO算法)到仿真对比测试的全过程。实验结果表明,RL控制器在动态响应、THD指标和参数鲁棒性等方面优于传统PI控制器,突显了数据驱动控制在复杂电力系统中的优势。文章还探讨了该技术在微电网协同控制、在线学习等场景的拓展应用,为智能电网控制提供了新思路。

MHD0815的博客 336

ISO21434 组织网络安全管理(二)

为了实现网络安全工程,该组织建立并维护网络安全治理和网络安全文化,包括网络安全意识管理、能力管理和持续改进。这涉及到指定针对本文档的目标进行独立审计的特定于组织的规则和过程。 为了支持网络安全工程,该组织实施了网络安全的管理系统,包括管理工具和应用质量管理系统。

qq_42357877的博客 1322

面试与压测问题汇总

回答框架(STAR 法则):背景 (S): XX公司业务线众多(金融租赁、保险、营销、物流、发票等),每个迭代需要大量回归测试,手工执行效率低、覆盖不全。任务 (T): 负责设计和开发公司级的 API 自动化测试平台,覆盖多条业务线的接口回归、流程编排和版本对比。基于 Spring Boot + TestNG + llrunner 搭建分层架构设计 Component → Flow → Factory → TestCase 四层架构。

weixin_46921460的博客 554

YOLOv8独家原创改进:原创自研 | 创新自研CPMS注意力,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

自研CPMS,多尺度通道注意力具+多尺度深度可分离卷积空间注意力,全面升级CBAM

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 3797

Java开发从入门到精通:环境配置与核心概念解析

Java作为面向对象的编程语言,其'一次编写,到处运行'的特性使其成为企业级开发的首选。理解Java运行原理需要从JVM虚拟机机制入手,掌握环境变量配置、基础语法和面向对象特性是开发者的基本功。在实际工程中,合理使用集合框架和并发编程能显著提升系统性能,而Java 8引入的Lambda和Stream API则大大简化了数据处理。对于初学者而言,正确配置JAVA_HOME环境变量和掌握数据类型转换是快速入门的关键,这些基础技能也为后续学习Spring等框架打下坚实基础。

weixin_30587927的博客 382

基于Python的电商平台商品信息爬取与价格监控系统设计与实现

本文详细介绍了一个基于Python的电商平台商品信息爬取与价格监控系统的设计与实现。系统采用最新的Python爬虫技术栈,包括Scrapy框架、Selenium自动化测试工具、BeautifulSoup解析库等,实现了对主流电商平台商品信息的自动化采集、存储、分析和可视化展示。文章从系统架构设计、关键技术实现、核心代码解析等方面进行了全面阐述,并提供了完整的代码实现。该系统不仅适用于毕业设计,也可作为商业价格监控系统的原型。关键词:Python爬虫;电商数据采集;价格监控;Scrapy;Selenium;

2201_76125261的博客 963

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Java&AI大模型面试题及答案整理(2026年金九银十最新版,持续更新)

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

m0_46995061的博客 239

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

上一篇: OpenWorm 智能蠕虫项目
下一篇: gdb 快捷键
Feisy
博客等级 码龄19年 166粉丝 235原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值