当前位置: 首页 > 面试题库 >

分配更多内存时,Python ctypes结构将被覆盖

濮阳原
2023-03-14
问题内容

在Python
3.2中,我将从ctypes.windll.kernel32.DeviceIoControl函数返回的数据中创建一个Structure对象。完成此操作后,我可以访问“结构”字段并返回数据。但是,如果我做某事会使用内存,例如打开文件,则会修改结构内部的数据。在输出的第一部分中,我粘贴的是预期的结果。但是,在打开文件并再次打印结构字段后,值已更改。我不确定为什么要修改数据或如何阻止它发生。

结构:

class DISK_GEOMETRY(ctypes.Structure):
    '''
    Disk Geometry Data Structure
    http://msdn.microsoft.com/en-us/library/aa363972(v=vs.85).aspx
    '''
    _fields_ = [("Cylinders", wintypes.LARGE_INTEGER),
                ("MediaType", wintypes.BYTE), #MEDIA_TYPE
                ("TracksPerCylinder", wintypes.DWORD),
                ("SectorsPerTrack", wintypes.DWORD),
                ("BytesPerSector", wintypes.DWORD)]


class DISK_GEOMETRY_EX(ctypes.Structure):
    '''
    Disk Geometry EX Data Structure
    http://msdn.microsoft.com/en-us/library/aa363970(v=vs.85).aspx
    '''
    _fields_ = [("Geometry", DISK_GEOMETRY),
                ("DiskSize", wintypes.LARGE_INTEGER),
                ("Data[1]", wintypes.BYTE)]

DeviceIoControl:

class DeviceIoControl:
    def __init__(self, path):
        self.path = path

    def __DeviceIoControl(self, devicehandle, IoControlCode, input, output):
        '''
        DeviceIoControl Function
        http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx
        '''
        DevIoCtl = ctypes.windll.kernel32.DeviceIoControl
        DevIoCtl.argtypes = [
            wintypes.HANDLE, #HANDLE hDevice
            wintypes.DWORD, #DWORD dwIoControlCode
            wintypes.LPVOID, #LPVOID lpInBuffer
            wintypes.DWORD, #DWORD nInBufferSize
            wintypes.LPVOID, #LPVOID lpOutBuffer
            wintypes.DWORD, #DWORD nOutBufferSize
            ctypes.POINTER(wintypes.DWORD), #LPDWORD lpBytesReturned
            wintypes.LPVOID] #LPOVERLAPPED lpOverlapped
        DevIoCtl.restype = wintypes.BOOL

        if isinstance(output, int):
            output = ctypes.create_string_buffer(output)

        input_size = len(input) if input is not None else 0
        output_size = len(output)
        assert isinstance(output, ctypes.Array)

        BytesReturned = wintypes.DWORD()

        status = DevIoCtl(devicehandle, IoControlCode, input, input_size, output, output_size, BytesReturned, None)
        return output[:BytesReturned.value] if status is not 0 else -1

    def GetDriveGeometry(self):
        diskhandle = winapi.CreateHandle(
                self.path,
                winapi.NULL,
                winapi.FILE_SHARE_READ|winapi.FILE_SHARE_WRITE,
                winapi.LPSECURITY_ATTRIBUTES(),
                winapi.OPEN_EXISTING,
                winapi.FILE_ATTRIBUTE_NORMAL,
                winapi.NULL)
        if diskhandle == winapi.INVALID_HANDLE_VALUE:
            return -1

        temp = ctypes.cast(self.__DeviceIoControl(diskhandle, winioctl.IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, None, 1024), ctypes.POINTER(winioctl.DISK_GEOMETRY_EX)).contents
        winapi.CloseHandle(diskhandle)
        return temp

主要:

device = DeviceIoControl(r"\\.\PhysicalDrive0")
devicegeo = device.GetDriveGeometry()
print("Disk Size: " +str(devicegeo.DiskSize))
print("BytesPerSector: "+str(devicegeo.Geometry.BytesPerSector))
print("Cylinders: "+str(devicegeo.Geometry.Cylinders))
print("MediaType: "+str(hex(devicegeo.Geometry.MediaType)))
print("CtypesAddressOf: "+str(ctypes.addressof(devicegeo)))

with open(r"\\.\PhysicalDrive0", 'rb') as f:
    f.seek(0)
    MBRdata = f.read(512)
print("\nOpened a file\n")

print("Disk Size: "+str(devicegeo.DiskSize))
print("BytesPerSector: "+str(devicegeo.Geometry.BytesPerSector))
print("Cylinders: "+str(devicegeo.Geometry.Cylinders))
print("MediaType: "+str(hex(devicegeo.Geometry.MediaType)))
print("CtypesAddressOf: "+str(ctypes.addressof(devicegeo)))

输出:

Disk Size: 80000000000
BytesPerSector: 512
Cylinders: 9726
MediaType: 0xc
CtypesAddressOf: 12322040

Opened a file

Disk Size: 0
BytesPerSector: 1
Cylinders: 2170477562872987649
MediaType: -0x40
CtypesAddressOf: 12322040

问题答案:

一些观察:

  1. DevIoCtl应该用来调用byref(BytesReturned)
  2. ctypes.cast的第一个参数必须是“可以解释为指针的对象”。但是,您要投射的是原始bytes对象(来自output[:BytesReturned.value])。
  3. 此时,您从中返回的__DeviceIoControl是一个新的Pythonbytes对象。对ctypes数组对象的原始引用已超出范围。因此,它很有可能已经被垃圾回收和/或重用。

FWIW,我只是使用ctypes尝试使用Windows
IOCTL调度。也使用\\.\PysicalDrive0IOCTL_DISK_GET_DRIVE_GEOMETRY

我做了这个要点。



 类似资料:
  • 问题内容: 使用以下Java选项启动Apache Tomcat(Atlassian Confluence)实例: 但是,我看到启动后,它很快就耗尽了虚拟服务器上可用的1GB内存中的大部分。 总消耗的内存(堆+ PermGen)是否不应该保持在使用- Xmx指定的值以下?这引起的问题之一是我无法使用关闭脚本关闭服务器,因为它试图生成具有256MB内存的JVM,该JVM因不可用而失败。 问题答案: T

  • 主要内容:一、基本的数据结构,二、Buffer Pool,三、Change Buffer,四、ADaptive Hash Index,五、Log Buffer,六、总结一、基本的数据结构 在InnoDB中,数据的分配和存储也有自己的数据结构,在前面分析过MySql中的内存管理,但是内存管理是有一个不断抽象的过程。在InnoDB中还会有一层自己的内存管理。在InnoDB引擎中的内存结构主要有四大类: 1、Buffer Pool 在MySql中,数据都是存储在磁盘中的,也就是说,从理论上讲,每次做S

  • 正如标题所说,我正在尝试为我的容器分配更多的内存。我正在使用docker中心的一个名为“aallam/tomcat-mysql”的图像,以防相关。 当我在没有任何特殊标志的情况下正常启动时,内存限制为2GB(即使我读到内存是无界的,如果没有设置) 这是我的码头工人数据 我试着像这样显式地设置内存,但结果相同 我已经读到,可能是虚拟机限制了它。但为什么docker统计数据显示容器大小限制为2GB?

  • 内存结构 一个C 程序本质上都是由BSS(Block Started by Symbol) 段、Data 段、Text 段三个组成的。 BSS 段:在采用段式内存管理的架构中,BSS 段(Block Started by Symbol)通常是指用来存放程序中 未初始化的全局变量的一块内存区域。BSS 是英文Block Started by Symbol 的简称。BSS 段属于静态内存 分配,即程序

  • 串的堆分配存储 ,其具体实现方式是采用动态数组存储字符串。 通常,编程语言会将程序占有的内存空间分成多个不同的区域,程序包含的数据会被分门别类并存储到对应的区域。拿 C 语言来说,程序会将内存分为 4 个区域,分别为堆区、 栈区、数据区和代码区,其中的 堆区是本节所关注的。 与其他区域不同,堆区的内存空间需要程序员手动使用 malloc 函数申请,并且在不用后要手动通过 free 函数将其释放。

  • 主要内容:1.运行时数据区,3.Java堆,4.方法区(Method Area)1.运行时数据区 运行时数据区 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分为若干个不同的数据区域。每个区域都有各自的作用。 分析 JVM 内存结构,主要就是分析 JVM 运行时数据存储区域。JVM 的运行时数据区主要包括:堆、栈、方法区、程序计数器等。而 JVM 的优化问题主要在线程共享的数据区中:堆、方法区。 1. 程序计数器 程序计数器(Program Counter