Python | 使用Pandas DataFrame时的内存泄漏问题及示例

Python | 使用Pandas DataFrame时的内存泄漏问题及示例

Pandas是一个功能强大且广泛使用的Python开源数据分析和操作库。它提供了一个DataFrame对象,允许您以非常直观的方式存储和操作行和列中的表格数据。Pandas DataFrames是处理数据的强大工具,但如果不小心使用,它们也可能成为内存泄漏的来源。

当程序分配了要使用的内存,但在不再需要时未能正确释放该内存时,就会发生内存泄漏。这可能会导致程序随着时间的推移使用越来越多的内存,从而可能导致性能问题,甚至导致程序崩溃。内存泄漏可能很难识别和诊断,但为了确保程序有效和正确地运行,避免内存泄漏是很重要的。

相关概念

DataFrame:DataFrame是一种二维的表格数据结构,具有行和列,可以以非常直观的方式存储和操作数据。它是Pandas库中的核心数据类型,旨在处理结构化的表格数据。

内存泄漏:当程序分配了内存供使用,但在不再需要时未能正确释放该内存时,就会发生内存泄漏。这可能会导致程序随着时间的推移使用越来越多的内存,从而可能导致性能问题,甚至导致程序崩溃。

pandas.DataFrame.memory_usage():此方法返回DataFrame对象使用的内存量。它可用于监视程序的内存使用情况,并识别使用的内存超过预期的任何DataFrame。

gc.collect():这个函数来自Python gc(垃圾收集)模块,强制垃圾收集器运行并释放程序中所有未使用的内存。通过确保正确释放未使用的内存以供重用,可以使用它来防止内存泄漏。

malloc_trim():malloc_trim是C标准库中的一个函数,可用于将未使用的内存释放回操作系统。此函数在Python ctypes模块中可用,该模块允许您调用动态链接库/共享库中的函数。malloc_trim可以用作gc.collect函数的替代方法来释放未使用的内存。但是,与gc. collect相比,它有一些局限性和差异。

正确删除DataFrame对象:为了避免在使用Pandas DataFrame时发生内存泄漏,正确删除程序不再需要的任何DataFrame对象非常重要。你可以在Python中使用del关键字来删除DataFrame对象并释放它所使用的内存。

只将需要的数据加载到DataFrame中:为了避免内存泄漏,应该只将实际需要的数据加载到DataFrame中。您可以使用pandas.read_csv()函数将数据从文件加载到DataFrame中,并指定要在DataFrame中包含的数据的列或行。这将防止未使用的数据在内存中累积并导致内存泄漏。

检测内存泄漏

为了保证有效的内存管理,Python程序必须检查内存泄漏。可以使用许多方法,包括内存分析和内存消耗监视。像memory_profiler和Pympler这样的工具可以用来发现内存使用趋势和潜在的泄漏。通过使用pandas.DataFrame.memory_usage()方法监视Pandas DataFrame内存使用情况,可以检测到意外的内存增加。

为了避免在使用Pandas DataFrames时发生内存泄漏,您应该遵循以下步骤:

  1. 使用del关键字显式删除不再需要的旧DataFrame对象。例如,如果您有一个名为df1的DataFrame,则可以使用以下代码删除它:del df1。
  2. 使用gc.collect()方法执行垃圾回收并释放未使用的内存。这在对大型DataFrame执行操作时尤其重要,因为内存使用量可能会很快变得非常大。
  3. 使用df.info()方法检查DataFrame的内存使用情况。这将使您给予DataFrame当前使用多少内存的感觉,并可以帮助您识别潜在的内存泄漏。

示例

以下是一些使用Pandas DataFrame时如何避免内存泄漏的示例:

示例1:

# Example 1 import pandas as pd import gc # Create a DataFrame df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) #Convert the data types of columns to save memory df['A'] = df['A'].astype(int8) df['B'] = df['B'].astype(int8) # Check the memory usage of the DataFrame df1.info() # Perform some operations on the DataFrame df1['C'] = df1['A'] + df1['B'] # Check the memory usage again df1.info() # Delete the old DataFrame del df1 # Perform garbage collection gc.collect() 

输出

<class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 A 3 non-null int8 1 B 3 non-null int8 dtypes: int64(2) memory usage: 176.0 bytes <class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 A 3 non-null int8 1 B 3 non-null int8 2 C 3 non-null int8 dtypes: int64(3) memory usage: 200.0 bytes 

示例2:

# Example 2 import pandas as pd import gc # Create a DataFrame df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) # Check the memory usage of the DataFrame df1.info() # Create a new DataFrame by performing some operations on the old one df2 = df1.groupby('A').sum() # Check the memory usage of the new DataFrame df2.info() # Delete the old DataFrame del df1 # Perform garbage collection gc.collect() 

输出

<class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 A 3 non-null int64 1 B 3 non-null int64 dtypes: int64(2) memory usage: 176.0 bytes <class 'pandas.core.frame.DataFrame'> Int64Index: 3 entries, 1 to 3 Data columns (total 1 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 B 3 non-null int64 dtypes: int64(1) memory usage: 48.0 bytes 

示例3:

# Example 3 import pandas as pd import gc # Create a DataFrame df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}) # Check the memory usage of the DataFrame df1.info() # Create a new DataFrame by # concatenating the old one with itself df2 = pd.concat([df1, df1]) # Check the memory usage of the new DataFrame df2.info() # Delete the old DataFrame del df1 # Perform garbage collection gc.collect() 

输出

<class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 A 3 non-null int64 1 B 3 non-null int64 dtypes: int64(2) memory usage: 176.0 bytes <class 'pandas.core.frame.DataFrame'> Int64Index: 6 entries, 0 to 2 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 A 6 non-null int64 1 B 6 non-null int64 dtypes: int64(2) memory usage: 144.0 bytes 

在每个示例中,在对DataFrame执行操作之前和之后都会检查DataFrame的内存使用情况。此外,使用del关键字删除旧的DataFrame,并使用gc.collect()方法执行垃圾收集。这些步骤有助于避免内存泄漏,并确保程序有效地使用内存。

要使用malloc_trim来释放Pandas DataFrame正在使用的内存,您可以按照以下步骤操作。

导入ctypes模块并从C标准库加载malloc_trim函数。删除对DataFrame的引用。使用零参数调用malloc_trim函数。这将释放以前使用malloc函数分配的所有内存,这些内存不再被应用程序使用。

示例4:

import ctypes import pandas as pd # Load the malloc_trim function from the C standard library malloc_trim = ctypes.CDLL("libc.so.6").malloc_trim # Create a large Pandas DataFrame df = pd.DataFrame({"col1": range(1000000), "col2": range(1000000)}) # Print the memory usage of the DataFrame print(f"Memory usage before deleting reference:\ {df.memory_usage().sum()} bytes") # Delete the reference to the DataFrame del df # Call the malloc_trim function with a zero argument malloc_trim(0) # Print the memory usage again to see if it has been released # (This will raise a NameError because df is no longer defined) print(f"Memory usage after calling malloc_trim:\ {df.memory_usage().sum()} bytes") 

输出

Memory usage before deleting reference: 16000128 bytes NameError: name 'df' is not defined 

malloc_trim不是释放Pandas DataFrame使用的内存的可靠方法,因为它只释放先前使用malloc函数分配的内存,而Pandas DataFrame使用的内存是使用其他函数分配的。要释放Pandas DataFrame使用的内存,您应该使用del关键字删除对DataFrame的引用,或者您可以使用gc.collect()函数运行垃圾收集器并释放内存。

其他内存优化策略

1.使用正确的数据类型:使用内存消耗较少的数据类型,如int 8和float 16,而不是标准的int 64和float 64。

# Convert the column data types to less memory occupying data types df_new['column1'] = df['column1'].astype('int8') df_new['column2'] = df['column2'].astype('float16') 

2.分类数据类型:利用pd.Categorical,将分类变量转换为分类数据类型以节省内存。

# Convert any column to the categorical data type column df['category_column_name'] = pd.Categorical(df['category_column_name']) 

3.稀疏数据结构:对于具有大量缺失值的数据,请使用稀疏数据结构(如Sparse DataFrame),因为它们可以保存大量内存。

# Create a Sparse DataFrame from pandas import SparseDataFrame df_sparse = SparseDataFrame(df) 

4.在存储或移动数据时考虑压缩数据。借助gzip等工具可以减少数据的内存占用。

# Compress dataframe using gzip df.to_csv('compressed_data.csv.gz', compression='gzip') 

Read more

前端防范 XSS(跨站脚本攻击)

目录 一、防范措施 1.layui util  核心转义的特殊字符 示例 2.js-xss.js库 安装 1. Node.js 环境(npm/yarn) 2. 浏览器环境 核心 API 基础使用 1. 基础过滤(默认规则) 2. 自定义过滤规则 (1)允许特定标签 (2)允许特定属性 (3)自定义标签处理 (4)自定义属性处理 (5)转义特定字符 常见场景示例 1. 过滤用户输入的评论内容 2. 允许特定富文本标签(如富文本编辑器内容) 注意事项 更多配置 XSS(跨站脚本攻击)是一种常见的网络攻击手段,它允许攻击者将恶意脚本注入到其他用户的浏览器中。

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

详细教程:如何从前端查看调用接口、传参及返回结果(附带图片案例)

目录 1. 打开浏览器开发者工具 2. 使用 Network 面板 3. 查看具体的API请求 a. Headers b. Payload c. Response d. Preview e. Timing 4. 实际操作步骤 5. 常见问题及解决方法 a. 无法看到API请求 b. 请求失败 c. 跨域问题(CORS) 作为一名后端工程师,理解前端如何调用接口、传递参数以及接收返回值是非常重要的。下面将详细介绍如何通过浏览器开发者工具(F12)查看和分析这些信息,并附带图片案例帮助你更好地理解。 1. 打开浏览器开发者工具 按下 F12 或右键点击页面选择“检查”可以打开浏览器的开发者工具。常用的浏览器如Chrome、Firefox等都内置了开发者工具。下面是我选择我的一篇文章,打开开发者工具进行演示。 2. 使用

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例)

Cursor+Codex隐藏技巧:用截图秒修前端Bug的保姆级教程(React/Chakra UI案例) 前端开发中最令人头疼的莫过于那些难以定位的UI问题——元素错位、样式冲突、响应式失效...传统调试方式往往需要反复修改代码、刷新页面、检查元素。现在,通过Cursor编辑器集成的Codex功能,你可以直接用截图交互快速定位和修复这些问题。本文将带你从零开始,掌握这套革命性的调试工作流。 1. 环境准备与基础配置 在开始之前,确保你已经具备以下环境: * Cursor编辑器最新版(v2.5+) * Node.js 18.x及以上版本 * React 18项目(本文以Chakra UI 2.x为例) 首先在Cursor中安装Codex插件: 1. 点击左侧扩展图标 2. 搜索"Codex"并安装 3. 登录你的OpenAI账户(需要ChatGPT Plus订阅) 关键配置项: // 在项目根目录创建.