Шаг 2. Удаление клиента
Аутентификация с помощью Azure Active Directory на powershell
Команды AzureAD [ 119]
a) connect-AzureAD -tenantid
Azure Active Directory -> Свойства -> ID каталога
b) Get-AzureADApplication
-> (+)
Для каждого приложения: [ 1112]
Remove-AzureADApplication -objectid
-> (+)
затем:
Remove-AzureADServicePrincipal -ObjectId
Azure Active Directory -> Удалить каталог -> Приложения Exterprise
Для каждого приложения Exterprise: нажмите на строку -> скопировать ID объекта =
в) В моем случае я смог удалить каталоги (арендаторы) после а) и б )
Для этого вам нужно будет использовать отражение . Полученный фрагмент кода слишком сложен для меня, чтобы публиковать его здесь (хотя он скоро будет доступен как часть инструментария GPL, который я создаю), но основная идея такова:
Вам нужно обрабатывать массивы отдельно (8 байтов заголовка, 4 байта поля длины, 4 * байта таблицы длины, плюс все, что используются внутри объектов). Вам нужно обрабатывать другие типы объектов, перебирая поля (и это родительские поля), используя отражение.
Похоже, что для этого уже есть утилита под названием Classmexer .
Я сам не пробовал, но я бы пошел по этому пути, прежде чем я свернул сам.
Хорошим общим решением является использование дельты размера кучи. Это требует минимальных усилий и может использоваться повторно для любого типа графа объекта / объекта. Создавая и уничтожая ваши объекты много раз и собирая мусор между ними, а затем беря среднее значение, вы избегаете оптимизаций компилятора и JVM, которые изменяют результаты и получают довольно точный результат. Если вам нужен точный ответ вплоть до байта, то это может не быть решением для вас, но для всех известных мне практических приложений (профилирование, расчеты требований к памяти) он работает очень хорошо. Код ниже сделает именно это.
public class Sizeof {
public static void main(String[] args)
throws Exception {
// "warm up" all classes/methods that we are going to use:
runGC();
usedMemory();
// array to keep strong references to allocated objects:
final int count = 10000; // 10000 or so is enough for small ojects
Object[] objects = new Object[count];
long heap1 = 0;
// allocate count+1 objects, discard the first one:
for (int i = -1; i < count; ++i) {
Object object;
//// INSTANTIATE YOUR DATA HERE AND ASSIGN IT TO 'object':
object=YOUR OBJECT;
////end your code here
if (i >= 0) {
objects[i] = object;
}
else {
object = null; // discard the "warmup" object
runGC();
heap1 = usedMemory(); // take a "before" heap snapshot
}
}
runGC();
long heap2 = usedMemory(); // take an "after" heap snapshot:
final int size = Math.round(((float)(heap2 - heap1)) / count);
System.out.println("'before' heap: " + heap1 +
", 'after' heap: " + heap2);
System.out.println("heap delta: " + (heap2 - heap1) +
", {" + objects[0].getClass() + "} size = " + size + " bytes");
}
// a helper method for creating Strings of desired length
// and avoiding getting tricked by String interning:
public static String createString(final int length) {
final char[] result = new char[length];
for (int i = 0; i < length; ++i) {
result[i] = (char)i;
}
return new String(result);
}
// this is our way of requesting garbage collection to be run:
// [how aggressive it is depends on the JVM to a large degree, but
// it is almost always better than a single Runtime.gc() call]
private static void runGC()
throws Exception {
// for whatever reason it helps to call Runtime.gc()
// using several method calls:
for (int r = 0; r < 4; ++r) {
_runGC();
}
}
private static void _runGC()
throws Exception {
long usedMem1 = usedMemory(), usedMem2 = Long.MAX_VALUE;
for (int i = 0; (usedMem1 < usedMem2) && (i < 1000); ++i) {
s_runtime.runFinalization();
s_runtime.gc();
Thread.currentThread().yield();
usedMem2 = usedMem1;
usedMem1 = usedMemory();
}
}
private static long usedMemory() {
return s_runtime.totalMemory() - s_runtime.freeMemory();
}
private static final Runtime s_runtime = Runtime.getRuntime();
} // end of class