Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.138.105.31] |
|
Сообщ.
#1
,
|
|
|
Эмпирическим путем 2 дня назад вывел максимальное число элементов в массиве до переполнения: 50102267. Сегодня - этот массив оказался неспособен к расширению даже до 33554432.
Что происходит? |
Сообщ.
#2
,
|
|
|
Вчера на машине ехал 150 - нормально. А сегодня на 20 уже трясёт так, что того и гляди развалится... а то, что вчера автобан, а сегодня просёлок, с машиной ну никак не связано. |
Сообщ.
#3
,
|
|
|
Цитата Сергей85 @ Что происходит? Фрагментация |
Сообщ.
#4
,
|
|
|
Цитата B.V. @ Цитата Сергей85 @ Что происходит? Фрагментация А почему происходит это? У меня 32 гига оперативки; ну не может ему не хватать разместить этот массив целым где-нибудь на 30-м гигабайте. Добавлено Цитата Akina @ Я не менял рабочую машину и кол-во запускаемых программ. Ребут тоже не помогает. |
Сообщ.
#5
,
|
|
|
Почитайте здесь:
|
Сообщ.
#6
,
|
|
|
Цитата __Sergey__ @ Мне для массива память надо заранее зарезервировать - и смогу запихнуть хоть 60миллионов значений? |
Сообщ.
#7
,
|
|
|
Цитата Сергей85 @ Мне для массива память надо заранее зарезервировать - и смогу запихнуть хоть 60миллионов значений? чем отличается виртуальная память от физической? |
Сообщ.
#8
,
|
|
|
Цитата __Sergey__ @ В моем случае это не важно: файл подкачки отсутствует. |
Сообщ.
#9
,
|
|
|
Цитата __Sergey__ @ чем отличается виртуальная память от физической? Цитата Сергей85 @ В моем случае это не важно: файл подкачки отсутствует. У каждого процесса\приложения свое собственное виртуальное адресное пространство (АП), в котором выделенные блоки памяти (регионы адресов) проецируются ОС на физ.память (ОЗУ или файл подкачки). Обычному 32-битному процессу доступно всего лишь 2 Гб виртуальных адресов независимо от разрядности ОС и размера ОЗУ. Причем в этих же 2 Гб размещаются не только пользовательские данные, но и код самого приложения и всех используемых им (явно или не явно) системных dll. Примеры распределения памяти процесса можно посмотреть в таблицах 13-2 и 13-3 по приведенной выше ссылке на Рихтера. Посмотреть распределение памяти в собственной программе можно с помощью утилиты VMMap от М.Руссиновича. Основным параметром, определяющим возможность выделения большого массива данных, является Free\Largest - размер свободного региона виртуальной памяти максимального размера. Если он меньше требуемого размера массива, то получишь Out of memory. Посмотри, чему у тебя равно это значение и изменяется ли оно от запуска к запуску |
Сообщ.
#10
,
|
|
|
Цитата Сергей85 @ В моем случае это не важно: файл подкачки отсутствует. |
Сообщ.
#11
,
|
|
|
Цитата leo @ Ну, пусть есть некая флуктуация некоей памяти при каждой перезагрузке. Но как проблему-то решить? Нужно массив будет 2^25 создать - как это сделать? Уж очень близко я к этому пределу подобрался. П.с.: 2^24 работают на всех машинах; проверил даже на старье 2ГБ RAM. |
Сообщ.
#12
,
|
|
|
Цитата Сергей85 @ Но как проблему-то решить? Нужно массив будет 2^25 создать - как это сделать? Чтобы решить проблему, нужно понять из-за чего она возникает. Одномерный массив double из 225 элементов имеет размер всего лишь 268 Мб - это слишком мало, чтобы облом мог происходить из-за начальной фрагментации АП из-за загрузки всевозможных dll. Скорее всего ты что-то не договариваешь - возможно у тебя не один массив, а несколько, или память под массив ты выделяешь не однократно, а несколько раз увеличиваешь его размер через Redim Preserve, или еще что ... Цитата Сергей85 @ проверил даже на старье 2ГБ RAM Размер RAM тут роли не играет - при отсутствии клинической фрагментации АП можно и при 2Гб RAM выделить непрерывный кусок памяти до 1.5-1.7 Гб |
Сообщ.
#13
,
|
|
|
Цитата leo @ 6 Dim dNumbers_Array() As Double, dFormula_Array() As Double, ... ReDim dFormula_Array(2 ^ (UBound(dNumbers_Array) + 1) - 2) 'Максимальная размерность массива (сумма по всем направлениям) - 50102267. 33554432 соответствует 2^25 как максимальному количеству анализируемых чисел. Значение "все нули" не используется. Всё. |
Сообщ.
#14
,
|
|
|
Цитата leo @ Сделал несколько массивов 2^23 + Copymemory для них. Не вылетает ничего. Я не понимаю, что мне мешает. Свободной RAM - десятки гигабайт. |
Сообщ.
#15
,
|
|
|
Цитата Сергей85 @ Я не понимаю, что мне мешает. Свободной RAM - десятки гигабайт. Сколько можно повторять, что размер RAM тут никакой роли не играет. Приложение работает не с RAM, а со своими виртуальными адресами, коих у 32-битного процесса всего лишь 2Гб, и часть из них занята различными служебными данными. Скачай VMMap по вышеприведенной ссылке и посмотри, что там у тебя творится с занятыми и свободными адресами. |
Сообщ.
#16
,
|
|
|
В общем, решил проблему структурой с кучей массивов по 2^23.
Задав похожие вопросы в других местах - люди ни на одном ПК не могли получить больше 2^27. Питон преуспел в этом больше всех. |
Сообщ.
#17
,
|
|
|
Цитата Сергей85 @ люди ни на одном ПК не могли получить больше 2^27. 227*8 = 1 Гб - для 32-битного приложения это нормально. А вот 223*8 - явно мало. Либо у тебя какие-то левые dll рубят все свободное АП на несколько малых кусков (что мало вероятно), либо ты сам со своими массивами где-то косячишь (что более вероятно). Все это можно легко проверить с помощью VMMap (запустить, сохранить отчет в txt и выложить сюда). |
Сообщ.
#18
,
|
|
|
Цитата leo @ Косячит хренова тонна программистов, попробовавших ПРОСТО СОЗДАТЬ массив 2^25? Я уже пишу не от лица 1 человека, а от 10-ти. |
Сообщ.
#19
,
|
|
|
Сообщ.
#20
,
|
|
|
Картинки VMMap ты привел совершенно не информативные. На них даже параметр Free\Largest block не виден, не говоря уже о занятых адресах (нужно хотя бы прокрутить нижний список до перехода адресов с 0ххх.. на Хххх..., чтобы увидеть причину фрагментации АП). Но лучше не картинки приводить, а сохранить данные VMMap через File\Save as в формате mmp и выложить их сюда, чтобы можно было увидеть всю картину\карту распределения памяти
Пример: в Excel 2002 пишу аналогичный макрос: массив 2^26 выделяет нормально, 2^27 - облом. Смотрю в VMMap и вижу причину - максимальный свободный блок составляет всего 688 Мб, прокручиваю адреса до перехода с 0ххх.. на Хххх.. и вижу, что причина в самом Excel.exe и прочих приблудах Office, которые грузятся по адресам ~300.. и рубят свободный блок АП ~1.4 Гб примерно пополам. Цитата Сергей85 @ Косячит хренова тонна программистов, попробовавших ПРОСТО СОЗДАТЬ массив 2^25? Ты уж определись - 2^25 или 2^27, т.к. разница очень существенная Добавлено PS: Единственная полезная инфа от выложенных картинок - это то, что свободный размер памяти у тебя превышает 2 Гб. Это говорит о том, что в твоей проге включен доступ к 3-му гигабайту (LARGE_ADDRESS_AWARE). Тем более не понятно, чем этот 3-й Гб занят, т.к. никакие dll обычно в него не грузятся ... |
Сообщ.
#21
,
|
|
|
2^26.
Прикреплённый файлDesktop.zip (37,91 Кбайт, скачиваний: 103) |
Сообщ.
#22
,
|
|
|
Цитата Сергей85 @ 2^26 Ну и ? В Project1 максимальный свободный блок памяти составляет 970 Мб, поэтому и "почему-то нет ошибки" при выделении 8*2^26 = 536 Мб. В vb6 максимальный блок равен 435 Мб (< 536 Мб), поэтому и происходит облом-с. Причина, как обычно, в дурных dll MS Office (в данном случае mso97rt.dll), которые норовят влезть по адресам вблизи 30000000H. Однако, хоть это и неприятно, но терпимо. Ты же уверяешь, что у тебя 2^24-2^25 не всегда выделяются, а это всего лишь 134-268 Мб - сколько еще нужно загрузить дурных dll, чтобы они так раздробили всё адресное пространство?! Можешь выложить пример, где с выделением 2^24-2^25 происходит облом? Насчет 3-го Гб я ошибся - макс.объем свободной памяти в Project1 не превышает 2Гб. Поэтому кардинальным решением проблемы в 64-битных ОС может быть разрешение для твоей программы использовать 3-й Гб (опция LARGE_ADRESS_AWARE). Это можно сделать с помощью утилиты editbin.exe, которая должна входить в состав VC6 (см. первый попавшийся пример). |
Сообщ.
#23
,
|
|
|
Option Explicit Option Compare Text Dim oExcelApp As New Excel.Application 'Приложение. Dim oDocExcel As New Excel.Workbook 'Документ Excel. Dim oExWs As New Excel.Worksheet 'Таблица документа Excel. Dim g_bCancel As Boolean 'Отмена ресурсоемкого процесса. Dim g_bCommand_Check_Click_Loaded As Boolean 'Самая ресурсоемкая функция завершила работу и успешно закрыла все приложения. Private Declare Function InitCommonControls Lib "Comctl32.dll" () As Long 'Для корректной загрузки COMCTL32.OCX в Windows XP. Private Declare Function GetDesktopWindow Lib "user32" () As Long Private Declare Function ShellExecute& Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long) 'Мгновенное копирование массивов. Private Sub Command_Check_Click() 1 On Error GoTo ErrorHandler 'Составление и заполнение массива данных. 3 Dim dNumbers_Array() As Double, dFormula_Array() As Double 'Открытие файла со списком номиналов. 20 g_oCommonDialog.FileName = "" 21 g_oCommonDialog.DialogTitle = "Открыть файл .XLS*" 22 g_oCommonDialog.Filter = "Файлы Microsoft Excel|*.xls*; *.csv" 23 If g_oCommonDialog.ShowOpen(Me) <> 0 Then Exit Sub 24 g_oCommonDialog.InitDir = g_oFSO.GetParentFolderName(g_oCommonDialog.FileName) 'Создать приложение Excel и скрытно работать с документом. 42 Set oExcelApp = New Excel.Application 43 oExcelApp.Visible = False 44 oExcelApp.IgnoreRemoteRequests = True 45 Set oDocExcel = oExcelApp.Workbooks.Open(g_oCommonDialog.FileName, , True) 46 Set oExWs = oDocExcel.ActiveSheet 'Работа построчно с передачей значений в функцию с формулами расчета. Количество комбинаций чисел - 2^n, что позволяет отказаться от факториалов и биномиального коэффициента. 47 While oExWs.Cells(lRow + 1, 1) <> "" 48 ReDim dNumbers_Array(0) 'Максимум чисел - 25. 49 dMaximum_Number = 0 50 iCol = 0 51 g_sTemp = "" 52 While oExWs.Cells(lRow + 1, iCol + 1) <> "" 53 If IsNumeric(oExWs.Cells(lRow + 1, iCol + 1)) Then 54 If iCol > 0 Then ReDim Preserve dNumbers_Array(iCol) 55 dNumbers_Array(iCol) = oExWs.Cells(lRow + 1, iCol + 1) 56 g_sTemp = g_sTemp & dNumbers_Array(iCol) & " " 57 If dMaximum_Number < dNumbers_Array(iCol) Then dMaximum_Number = dNumbers_Array(iCol) 58 Else 59 MsgBox "Ошибка: в строке " & lRow + 1 & " стоблце " & iCol & " указано не положительное число. Операция прервана, результаты на экране." 60 GoTo endd 61 End If 62 iCol = iCol + 1 63 Wend 64 [B]ReDim dFormula_Array(2 ^ (UBound(dNumbers_Array) + 1) - 2) 'Значение "все нули" не используется.[/B] Добавлено Не понимаю, как LARGE_ADRESS_AWARE подключается? По примеру фигня какая-то. Ведь получается, что проект должен вызвать editbin сам на себя. |
Сообщ.
#24
,
|
|
|
Используя небольшую хитрость на 64 битных системах можно выделить больше 4ГБ памяти.
|
Сообщ.
#25
,
|
|
|
Цитата TheTrik @ Иииии?.. |
Сообщ.
#26
,
|
|
|
Цитата Сергей85 @ Иииии?.. Учитывая что любой процесс в 64 битной среде является 64 битным, включая 32 битные то мы можем использовать все преимущества 64 битного режима из 32 битного процесса. Именно для выделения памяти нужно переключится в 64 битный режим, найти ntdll, найти функцию NtAllocateVirtualMemory, вызвать ее, получить указатель в 64 битном пространстве, переключится обратно. Писать/читать либо переключаясь в 64 битный режим либо с помощью функций NtWow64WriteVirtualMemory64/NtWow64ReadVirtualMemory64. |
Сообщ.
#27
,
|
|
|
Цитата Сергей85 @ Не понимаю, как LARGE_ADRESS_AWARE подключается? LARGE_ADRESS_AWARE подключается путем простой установки флага в заголовке exe-файла. В продвинутых компиляторах это делается путем задания соответствующей опции линкера. В vb6 такой возможности нет. Поэтому нужно использовать утилиту editbin.exe, которая установит нужный флаг в уже готовом\скомпилированном экзешнике. Для этого нужно в винде выполнить команду "путь\editbin.exe /largeaddressaware путь\имя_твоей_проги.exe". Чтобы каждый раз не набирать эту абру-кадабру, можно в папке с твоей программой создать либо bat-файл (простой текстовый файл с расширением bat) с соответствующей строкой, либо ярлык для editbin.exe, в котором через Свойства изменить строку Объект - добавить " /largeaddressaware имя_твоей_проги.exe". А чтобы не забыть про все это дело, можно в проге добавить вызов функции GlobalMemoryStatusEx (как рекомендовано в примере) с выдачей предупреждения в случае ullTotalVirtual <= 2 Гб. |
Сообщ.
#28
,
|
|
|
Замечания по коду #23.
1) Тебе уже в соседней ветке указали на то, что объявлять переменные oExcelApp, oDocExcel и oExWs через New не нужно, т.к. во-первых, это не имеет смысла, поскольку в Command_Check_Click ты их все равно устанавливаешь заново, во-вторых, создание Excel.Workbook и Worksheet через New может приводить к той самой ошибке 429 - "ActiveX component can't create object". 2) Я уже говорил, что вызов диалога открытия файла подгружает кучу разных dll (в том числе и совершенно левых, отвечающих за опции контекстного меню файла) и создает несколько потоков - все это может негативно сказываться на фрагментации адресного пространства твоей проги. Работа с объектами Excel также может приводить к подгрузке офисных dll, созданию расшареных регионов памяти и т.п. Поэтому, раз у тебя максимальный размер массива dFormula_Array не может превышать 2^25*8 = 268 Мб (по сути - это "мелочь пузатая"), то лучше выделить память под него сразу при старте проги (до вызова диалога открытия файла и создания объектов Excel - например, в Form_Load). Если в Command_Check_Click окажется, что для массива нужно меньше памяти, то можно сделать ReDim для уменьшения его размера (только без Preserve - иначе м.б. облом!) PS: Наращивать длину массива dNumbers_Array по одному элементу, когда их максимальное число не может превышать 25 - это как-то э-э-э, "не профессионально". Проще использовать статический массив (можно с запасом, например на 32 элемента), а реальное кол-во используемых элементов хранить в отдельной переменной типа dNumbers_Count As integer |
Сообщ.
#29
,
|
|
|
1) Пробовал с разными вариантами перетасовки New - ошибка не меняется.
2) Ясно. PS: что быстрее: Ubound(Array) или int при указании в условиях цикла For? Мне скорость циклов важнее, чем скорость заполнения массива dNumbers. |
Сообщ.
#30
,
|
|
|
Цитата Сергей85 @ что быстрее: Ubound(Array) или int при указании в условиях цикла For? Теоретически int "быстрее", но практически в цикле For ты разницы не заметишь, т.к. при For верхний предел (по идее) должен вычисляться только один раз перед входом в цикл (а не на каждой итерации как в while и do..loop) |
Сообщ.
#32
,
|
|
|
Извините за оффтоп. Сергей, ты наверно один остался на VB6? Может подумаешь?
|
Сообщ.
#33
,
|
|
|
Цитата AndreyMp @ Сергей, ты наверно один остался на VB6? Осталось много, он один, кто активно спрашивает. |