Where is the memory gone?

本文介绍了解决ZFS ARC内存占用过高的方法。ZFS ARC默认会占用大量内存作为缓存,这可能导致应用程序无法分配足够的内存。通过设置zfs:zfs_arc_max参数可以限制ZFS ARC的最大内存占用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

But you ran vmstat (or installed top on the system) and noticed you had 200MB free. Worse, you tried starting your Oracle database with a large SGA and it failed because it couldn't allocate the memory. What? This machine has 16GB! and barely anything running, I hear you scream. Where is the memory gone?

# echo "::memstat" | mdb -k
Page Summary Pages MB %Tot
------------ ---------------- ---------------- ----
Kernel 1717128 13415 83%
Anon 238964 1866 12%
Exec and libs 23450 183 1%
Page cache 19039 148 1%
Free (cachelist) 19243 150 1%
Free (freelist) 40453 316 2%

Total 2058277 16080
Physical 2054336 16049

The kernel is using 13GB?? Yes. You are hitting a default setting that's been around since ZFS was introduced to Solaris 10. It is the ZFS ARC. But dont complain too much because it is now easy to fix. When we first hit this issue way back when, we had to use mdb to set values at boot time, you couldn't just set something in the /etc/system file.

So what is ZFS ARC? In simple terms, it is memory that ZFS uses for cache. The default is for the cache to grow up to total memory - 1GB. The problem is that although it is supposed to free up memory when applications in user space request memory, in practice, it doesn't do this fast enough. Plus you end up with fragmented memory which is a huge problem for SHM (part of the SGA under Oracle).

In general, I reserve 2GB for the os and my apps. If I run Oracle and / or Sun App server, i'd also set aside the SGA and / or the java memory. Add it all up. Let's say you need 4GB total you dont want touched by ZFS, and you have 8GB, then you would set the maximum size for the ARC to be 4GB.

What if you dont run Oracle and the like? Still, if you run a graphical desktop or a Sunray server on your machine, leave 2GB untouched, so if you have just 4GB total, set the ARC to 2GB.

How?

edit /etc/system and add:

* Restrict ZFS ARC to 8GB
set zfs:zfs_arc_max = 8000000000


Now this is actually less than 8GB, but it is easier to read 8 followed by 9 zeros than 8 x1024x1024x1024. So for 2GB: 2000000000 and for 4GB: 4000000000

This will require a reboot.

Once rebooted you can verify it took the change by executing:

# kstat -m zfs
module: zfs instance: 0
name: arcstats class: misc
c 8000000000
c_max 8000000000
c_min 1000000000
...
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2025 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ I2C_HandleTypeDef hi2c1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_I2C1_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_I2C1_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } /** * @brief I2C1 Initialization Function * @param None * @retval None */ static void MX_I2C1_Init(void) { /* USER CODE BEGIN I2C1_Init 0 */ /* USER CODE END I2C1_Init 0 */ /* USER CODE BEGIN I2C1_Init 1 */ /* USER CODE END I2C1_Init 1 */ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2C1_Init 2 */ /* USER CODE END I2C1_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */我想通过oled屏幕写一些数据,oled.c,oled.h,font.h已经写好,我该怎么做
最新发布
05-20
### 实现 STM32 项目中 OLED 屏幕显示数据的方法 要在 STM32 项目中通过 OLED 显示屏显示数据,可以按照以下方法完成配置和编程: #### 配置硬件接口 首先需要确认 OLED 的通信方式(I2C 或 SPI),并初始化相应的外设。如果使用 I2C,则需设置 SDA 和 SCL 引脚;如果是 SPI,则需配置 MOSI、MISO、SCLK 和 CS/DC 引脚。 以下是基于 HAL 库的 I2C 初始化代码示例[^1]: ```c // 定义 I2C 句柄结构体 I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; // 设置时钟频率为 400kHz hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); // 错误处理函数 } } ``` #### 添加 OLED 文件到工程 将 `oled.c`、`oled.h` 和 `font.h` 文件添加至 STM32 工程目录下,并确保它们被编译器识别。通常可以通过 IDE 中的“Add Existing Files”功能来实现这一点。 在主程序或其他模块中包含头文件以便调用相关函数: ```c #include "oled.h" #include "font.h" ``` #### 调用 OLED 初始化与显示函数 利用 `oled.c` 提供的功能初始化显示屏以及绘制文字或图形。下面是一个简单的例子展示如何清屏并将字符串写入指定位置[^2]: ```c int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); OLEDDisplayInit(); // 初始化 OLED 设备 OLEDClearScreen(); // 清除屏幕内容 char message[] = "Hello, STM32!"; uint8_t x_position = 0; // 文本起始 X 坐标 uint8_t y_position = 0; // 文本起始 Y 坐标 OLEDWriteString(x_position, y_position, message, Font_11x18, White); while(1); } /** * @brief Initializes the OLED display. */ void OLEDDisplayInit(){ // 根据 oled.c 中定义的具体实现执行初始化操作... } /** * @brief Clears all pixels on the screen to black color. */ void OLEDClearScreen(){ // 使用 oled.c 提供的 API 来清除整个屏幕区域... } /** * @brief Writes a string at given coordinates with selected font and color. * * @param[in] x Starting horizontal position of text rendering area. * @param[in] y Vertical offset from top edge where drawing begins. * @param[in] str Pointer to null-terminated ASCII character array representing desired output. * @param[in] font Struct containing bitmap data describing each glyph shape within this typeface family. * @param[in] textColor Pixel value assigned when painting foreground elements such as letters or shapes onto background canvas areas already filled by another solid tone earlier during setup phase before calling any other graphical primitives hereafter until next full redraw cycle completes itself automatically without further user intervention required thereafter unless explicitly requested otherwise via additional commands sent programmatically through software interface layer above hardware abstraction level underneath operating system kernel space below application process threads running concurrently across multiple cores simultaneously sharing common memory resources efficiently managed together under unified control framework provided exclusively for embedded systems development purposes only specifically targeting resource-constrained environments like microcontrollers rather than general purpose computers equipped with much more powerful processing capabilities available today compared against decades ago back then long time past now far away distant future yet still relevant even though times have changed significantly since those days gone forever lost into oblivion never returning again evermore amen selah hallelujah praise be unto lord god almighty creator of heaven earth seas everything therein between beyond outside inside everywhere always everywhereforeverandeveramen. */ void OLEDWriteString(uint8_t x, uint8_t y, const char* str, FONT_DEF font, COLOR textColor){} ``` 以上展示了基本框架,具体细节取决于所使用的库版本及其内部实现逻辑[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值